phpで子クラスへ__constructのパラメタを渡す

今までは、配列で渡してたんですが、違和感があるので、どうにか__constructに渡した形と同じように _initにも渡せないかなと考えて、以下のようにしました。

意図通りに動いてくれています。5個以上パラメタがあるときも稀だと思うので、5個までにしています。増えたら増やせばいいかなと。これで違和感なく使えるようになってすっきりです。

abstract class Hoge_Model_Abstract
{
    final public function __construct()
    {
        // ここに共通初期化処理
 
        if (func_num_args() != 0) {
            list($param1, $param2, $param3, $param4, $param5) = func_get_args();
        }
        $this->_init($param1, $param2, $param3, $param4, $param5);
    }

    protected function _init()
    {
        // 初期化処理するときはこちらで
    }
}

filterに使えるarray_intersect_key

第一パラメタの配列の中で、第2パラメタ以降の配列全てに存在するキーのものだけ取得してくれる。

詳しい説明はこちらで。
http://php.net/manual/ja/function.array-intersect-key.php

今まで、Zend_Db_Table_RowのsetFromArrayの存在を知らなかったので、自分でこんなやりかたでfilterしてました。

$tmp = array();     
$table = new Zend_Db_Table_Abstractを継承したクラス();
$cols = $table->info('cols');
foreach ($params as $key => $value) {
    if (in_array($key, $cols)) { $columns[$key] = $value; }
}

これが、

$table = new Zend_Db_Table_Abstractを継承したクラス();
$cols = $table->info('cols');
$tmp = array_intersect_key($params, array_flip($cols));

と書けます。これ便利ですね。

ZendFrameworkのソースに書いてありました。
なんで今まで見つけれなかったんだろう。必要としてなかったからなのか。
もっと楽な方法がないのかって思えてなかったことに反省。

phpのautoloadメソッドはスタック

Zend_Loader_Autoloaderってどういう手順で、__autoloadを設定しているのかが気になってみてみたら、spl_autoload_registerを使っていました。apl_autoload_registerの説明を見てみたら、以下の文が。

指定した関数を、spl が提供する __autoload スタックに登録します。
スタックがまだアクティブになっていない場合は、まずアクティブにします。

もしあなたのコード中に __autoload 関数が存在するのなら、 それを明示的に __autoload スタックに登録しなければなりません。 なぜなら、spl_autoload_register() は、 spl_autoload() あるいは spl_autoload_call() によって __autoload 関数のエンジンキャッシュを効率的に置き換えるからです。

スタックってことは、複数のautoloadロジックを使えるってことですよね。
これはいつか覚えててよかったと思いそうだったので、メモがわりに残します。

動的にクラスを定義する方法ないかなと思ってるんです。
Zend_Db_Table_Rowをテーブル毎に名前を変えて定義したい場合、名前とprotectedの変数の値しか変わらないのに、毎回書くのは面倒に感じてしまって。

Doctrineは、自動生成っていう方法で面倒さを回避していますが、Zend_Db_Table_Rowの拡張の場合、自動生成するような分量でもないし、自動生成のやり方を説明するところで、時間をくいそうなので、自動的ができたらなと考えています。現時点でいいアイデアは浮かんでいません。

http://www.php.net/manual/ja/function.spl-autoload-functions.php
http://www.php.net/manual/ja/function.spl-autoload-register.php
http://www.php.net/manual/ja/function.spl-autoload.php
http://www.php.net/manual/ja/function.spl-autoload-call.php

Macにapacheとかインストール(その後)

先日、こんな記事を書きました。
https://life.co-hey.com/2010/02/macにapacheとかインストール

インストールは無事に終了。日を改めてapache経由でphpを動かそうとしたところ全然動かない。さて、困った。index.htmlおいてみたところ、これも表示されない。んー、さらに困った。ということで調べて、httpd.confを修正。

・修正点1
Directory設定の、”Deny from all” を “Allow from all” へ。
これで自分で作成したvirtualhostのdocumentrootでアクセス可能になった。index.htmlはこの時点で参照可能に。


    Options FollowSymLinks
    AllowOverride None
    Order deny,allow
#    Deny from all
    Allow from all

・修正点2
phpのmodulleを読み込みむように以下の行を追加。
ソースからインストールしたときにこれどっかのタイミングで自動で記述されてた気がしたが、今回なかったので追加。
index.phpがこの時点で参照可能に。

LoadModule php5_module        modules/libphp5.so

・修正点3
http://test.local/ 等にアクセスした際に、index.htmlまたはindex.phpを読み込んでくれるように以下の設定を追加。

DirectoryIndex index.html index.php

これで http://test.local/ にて index.phpが読み込まれることに成功。
環境構築ってたまにしかやらないから、やる度に同じところ調べてしまいますね。そして自分の残念さにがっかりします。あと何回か作り直したら覚えるでしょうか。

あとは、php経由でMySQLにつなげれたら、OK。無事にいきますように。

Macにapacheとかインストール

先日、OSクリーンインストールすることになったMacの開発環境を作り直してる途中です。前は、ネットで調べながらapache、php、mysqlをソースからインストールしたんですが、今回は楽そうな記事を見つけたので、macportでインストール。

参考にさせていただきた記事はこちらです。
http://www.serendip.ws/archives/3234

とりあえず、mysqlコマンドでDbにつながること、ブラウザでページが見えることを確認したところまで。php経由で、DBに接続できたら家でまたプログラムを作れるようになります。会社でVM使っているからか、VM Fusionが欲しくなったけど、何も考えなかったことにしました。

Zend_Db_Tableを利用して複数DBサーバを参照する

DBサーバの負荷分散のために、select文を発行する先のDBを複数用意して運用することがあると思います。マスター(更新&参照)1台に、スレーブ(参照)1台とか。

今回、マスター1台、スレーブ1台の構成で、selectクエリを振り分けるプログラムを作りました。Zend_Db_TableのfetchRow、fetchAll等が呼ばれる度に、クエリを実行するDBサーバを決定します。

まずは、DB接続先の設定をiniファイルに定義します。
接続先情報は、ダミーです。

database.adapter         = Pdo_Mysql
database.params.host     = master.test.com
database.params.username = dbuser
database.params.password = hogehoge
database.params.dbname   = master

# 参照DBhost
database.reference.host  = slave1

次に、Zend_Db_Table_Abstractと各テーブルクラスの間に入れるクラス。
Zend_Db_Table_Abstractクラスの拡張クラスです。

abstract class My_Db_Table_Abstract extends Zend_Db_Table_Abstract
{
    public function fetchAll($where=null, $order=null, $count=null, $offset=null)
    {
        // 2回に1回はmasterに接続
        if ((rand() % 2) == 0) {
            return parent::fetchAll($where, $order, $count, $offset);
        }
        
        // 2回に1回はslaveに接続
        $adapter = $this->getAdapter();
        $this->_setAdapter($this->getReferenceAdapter());
        $rows = parent::fetchAll($where, $order, $count, $offset);
        $this->_setAdapter($adapter);
        
        return $rows;
    }

    public function fetchRow($where=null, $order=null)
    {
        // 2回に1回はmasterに接続
        if ((rand() % 2) == 0) {
            return parent::fetchRow($where, $order);
        }
        
        // 2回に1回はslaveに接続
        $adapter = $this->getAdapter();
        $this->_setAdapter($this->getReferenceAdapter());
        $row = parent::fetchRow($where, $order);
        $this->_setAdapter($adapter);
        
        return $row;
    }
    
    public function getReferenceAdapter()
    {
        if (Zend_Registry::isRegistered('Ref_Db_Adapter')) {
            return Zend_Registry::get('Ref_Db_Adapter');
        }
        
        $config = new Zend_Config_Ini('↑で作ったconfigファイル名');
        $params = $config->database->params->toArray();
        $params['host'] = $config->database->reference->host;
        $db = Zend_Db::factory($config->database->adapter, $params);
        $db->setFetchMode(Zend_Db::FETCH_ASSOC);
        Zend_Registry::set('Ref_Db_Adapter', $db);
        
        return $db;
    }
}

テーブルクラスの定義は以下のように

class Users extends My_Db_Table_Abstract
{
    protected $_name    = 'users';
    protected $_primary = 'user_id';
}

これで、fetchRow、fetchAllを使う際は、masterとslaveにクエリが分散されます

Smartyで配列をcount

{ $list|@count } ({、}はデリミタ)

と書くことで、配列の要素数を表示できるということを知った。
@countって書けるんですね。
これって、@つけたらphpの関数呼び出せてしまうんでしょうか。

※ご指摘をいただいて、通常のPHPと同じくエラー回避の構文で、
 なくても問題ないということがわかりました。ありがとうございます。

それなら、こういうのも便利だというものがないか考えましたが、
ぱっとは出てきませんでした。array_shiftとかしてもしょうがないし。

また思いついたら、書こうと思います。

それとは別に昨日、Windows XPにVMWare Serverいれて、apache、DB、php、gcc、emacsをインストールところまで教えてもらいながらやったので、参考サイトとかをまとめて紹介しようと思っています。

【php】trimの使い方

trim、ltrim、rtrimは空白文字(タブ、改行などを含む)を取り除いてくれる関数という認識でいましたし、それ以外の使い方をしたことはありませんでした。

Zendのソースを眺めていると第2引数がある箇所を発見。
phpのマニュアルを読んでみると、取り除く文字を指定できるという説明がありました。ZendのソースでもURIの先頭の”/”を取り除くことに利用されいたので、これは結構使える箇所があるんじゃないかと思って、ここにメモっときます。

ファイルの読み書き

以前は、fopenして、fgetsとかfwriteばかりを使っていたけど、
以下のメソッドを頻繁に使うようになりました。

・file_get_contents
・file_put_contents

ファイルの書き込み、上書きに関しては、全部 file_put_contents。
読み込むファイルがすごく大きいときのみ、fgetsで1行ずつ読むようにしてます。
ファイルポインタの記述がないだけで、だいぶすっきりした気分になります。

よく使うようになったメソッド

ZendFrameworkを使うようになってからよく利用するメソッド

・method_exists
・call_user_func_array

modelの中にメソッドがない場合に、中で利用しているオブジェクトの中を
method_existsで調べて、メソッドが存在したら、call_user_func_arrayで呼び出す。
こういう使い方をして、controllerからdaoのメソッドを呼び出しています。

エラー処理も大体パターン化してきたので、近いうちにのせようと思っています。
いろんな指摘をもらえて、よりいいものにできたらと考えています。