読者です 読者をやめる 読者になる 読者になる

事務員、プログラマーになる

事務員がプログラマーになりました。

SQLの「?」と戦う② 直す編

CodeIgniter3

書いている構文から、「?」に検索条件を置き換えているのは

$this->db->query($sql, $binds)

のqueryで間違いないと思います。

systemフォルダの中をあさってみると
CI_DB_driverというクラスにqueryファンクションが存在しました。
さらに実際の置き換え処理をしているのがcompile_bindsファンクションのようです。

teratailで教えて頂いたサイト様を参考にCI_DB_driverを拡張しようとしたのですが、何度やってもうまくいきません。
わざと?を全部「あ」に置き換える処理にしてみても呼ばれてる気配がない。
これはおかしい・・・。

ということでソースをうんうん眺めていたのですが、気になったのが

abstract class CI_DB_driver {

abstractって…私が作ったクラスにはついてないけどなんだコレ。

抽象クラスというらしいですが、説明を何回読んでもサッパリ意味がわかりません。
わからないけど、要するにこれだけじゃ何もできなくて、継承しないと使えないもの?

その観点から「CI_DB_driver」でファイルを全部検索すると
↓こんなとこが見つかりました。

 if ( ! isset($query_builder) OR $query_builder === TRUE)
    {
        require_once(BASEPATH.'database/DB_query_builder.php');
        if ( ! class_exists('CI_DB', FALSE))
        {
            /**
             * CI_DB
             * Acts as an alias for both CI_DB_driver and CI_DB_query_builder.
             * @see    CI_DB_query_builder
             * @see    CI_DB_driver
             */
            class CI_DB extends CI_DB_query_builder { } // ここと
        }
    }
    elseif ( ! class_exists('CI_DB', FALSE))
    {
        /**
         * @ignore
         */
        class CI_DB extends CI_DB_driver { } // ここ
    }

おぉ…名前からして$this-dbのdbの本体がこのCI_DBのようだ・・・・。 いくらCI_DB_driverを拡張しても何の意味もないのは実態はCI_DBで、継承してるのは拡張してない本体だからという呼ばれないのかも。

そこでteratailでおしえて頂いたサイト様の以下を参考に a-zumi.net CI_DB_query_builderを継承したMY_DB_query_builder作成。

これで、本題だったcompile_bindsが上書きできるようになりました!!

↓こんな感じ

public function compile_binds($sql, $binds){
    $sql = parent::compile_binds($sql, $binds);
    
    if (array_values($binds) !== $binds) {
        foreach($binds as $key => $value){
            $escaped_value = $this->escape($value);
            if (is_array($escaped_value)){
                $escaped_value = '('.implode(',', $escaped_value).')';
            }
            $sql = str_replace(':'.$key, $escaped_value, $sql);
        }
    }
    return $sql;
}

最初にparentのファンクションを呼び出したので、?も置き換えてもらえました。 置き換え処理は親クラスを真似したのでたぶん大丈夫。 $escaped_valueをが配列かどうか判定している部分が何になるのか、さっぱりわかりません。 親クラスがやってたので真似しました。

これで目標は達成できましたが、abstractクラスというのが一体何のために使われるのかわかりません。 興味がわいて調べてみたら、ちょっと面白そうだったので、次はそれに挑戦してみます。