便利だけど使いどころが難しいPHPの代表的なマジックメソッドと無名関数の使い方:PHPオブジェクト指向プログラミング入門(4)(2/3 ページ)
「PHPで、どのようにオブジェクト指向プログラミングをしていくか」を解説する連載。今回は、マジックメソッドの概要と__get()、__set()、__call()、__callStatic()、__toString()の書き方と使い方に加え、PHP 5.3から使えるようになった無名関数と__invoke()について解説します。
アクセス不能メソッドを実行する__call()と__callStatic()の使い方
続いて、「__call()」「__callStatic()」を見ていきましょう。
この二つはアクセス不能メソッドを実行しようとしたときに呼ばれます。インスタンスからの実行であれば__call()が、クラス名からの、静的コンテキストでの実行であれば__callStatic()が呼ばれます。
__get、__setと同様、マジックメソッドが存在しないコードとマジックメソッドが呼ばれるコードを見てみましょう。
まずは__call()と__callStatic()が存在しないコードです(リスト7)。
<?php // class hoge { } // $obj = new hoge(); $obj->func(); hoge::func_static();
実行すると、「Fatal error: Call to undefined method hoge::func()」「Fatal error: Call to undefined method hoge::func_static()」というエラーが出ます。
では、ここにマジックメソッドを追加してみましょう(リスト8の4〜11行目)。
<?php // class hoge { public function __call($name, $args) { echo "call {$name}\n"; var_dump($args); } public static function __callStatic($name, $args) { echo "callStatic {$name}\n"; var_dump($args); } } // $obj = new hoge(); $obj->func(); hoge::func_static();
実行すると、下記のようになります。
call func array(0) { } callStatic func_static array(0) { }
引数を渡した場合、引数は全て、第二引数に配列で入ってきます。簡単に確かめてみましょう。
<?php // class hoge { public function __call($name, $args) { echo "call {$name}\n"; var_dump($args); } public static function __callStatic($name, $args) { echo "callStatic {$name}\n"; var_dump($args); } } // $obj = new hoge(); $obj->func(1, 2, 'abc', array(1,2,3)); hoge::func_static(1, 2, 'abc', array(1,2,3));
実行すると、結果9のようになります。
call func array(4) { [0]=> int(1) [1]=> int(2) [2]=> string(3) "abc" [3]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } } callStatic func_static array(4) { [0]=> int(1) [1]=> int(2) [2]=> string(3) "abc" [3]=> array(3) { [0]=> int(1) [1]=> int(2) [2]=> int(3) } }
__callや__callStaticは、例えば「モックオブジェクト(ユニットテストなどで使われる、スタブ(下位モジュールの代用品)の一種)」を作るときなどに便利です。それ以外ですと、__callを使って比較的手軽にアクセサーを作ることも可能です。
細かい話ですが__callや__callStaticを使うと、ちゃんとプロパティとメソッドを個々に書くのと比較して若干、処理が重くなります。一方で、特に開発序盤〜中盤などでプロパティの増減が激しいときなど、「いったん、__callを使って実装して、ある程度仕様が落ち着いてから書き直す」などの方法も採れますので、手法として覚えておいて損はないでしょう。
実装例としてリスト10を書いてみますので、参考にしていただければと思います。
<?php // class hoge { public function __construct() { $this->data_ = array(); // 使いたいプロパティ名の設定 $this->propertys_ = array ( 'foo' => 1, 'bar' => 1, 'data' => 1, ); } // 疑似アクセサー用の__call() public function __call($name, $param) { if ( (0 === strncmp($name, 'get', 3))||(0 === strncmp($name, 'set', 3)) ) { $type = substr($name, 0, 3); $k = strtolower(substr($name, 3)); if (false === isset($this->propertys_[$k])) { // XXX 適宜エラー処理 throw new Exception('えらー'); } // else if ('set' === $type) { $this->data_[$k] = $param[0]; } else { return $this->data_[$k]; } } else { // XXX 適宜エラー処理 throw new Exception('えらー'); } } //private: private $propertys_; private $data_; } // $obj = new hoge(); $obj->setData(100); echo $obj->getData() , "\n"; // //$obj->setTest(100); // コメントを外すとエラー
後は「$this->propertys_」のkeyに使いたい変数名を追加すると、疑似的にですがアクセサーが自動で追加されていきます。これに、前述の__setと__getを使って、存在しないプロパティへのアクセスを防御する方法を組み合わせると、割と安全な基底クラスを作成できます。
こういった手法を覚えておくと、特に、ちょっと時間がタイトな開発などで、役に立つでしょう。
Copyright © ITmedia, Inc. All Rights Reserved.
関連記事
- 初心者がPHPプログラミングを始めるための基礎知識とXAMPPのインストール
オープンソースのWeb開発向けスクリプト言語「PHP」の文法を一から学ぶための入門連載。初回は、PHPの概要や特徴を紹介し、環境構築や「Hello World!」までの手順などを解説します【PHP 7.1含め2017年の情報に合うように対応、XAMPP環境構築を追記】。 - PHP編に突入! まずはソースをダウンロード
今回からPHPのビルドとインストールに入ります。まずはPHPという言語の概要と、ソースコードの入手法を解説します(編集部) - 理論編:PHPについて知ろう
スクリプトを記述するだけの簡単なプログラミングで、Web対応の高速なデータベースアプリケーションを実現する手法としてPHPが急速に注目を集めている。しかもデータベースはオープンソースのPostgreSQLだけでなく、Oracleなどの商用データベースも扱える。ここでは、5月にバージョンアップしたばかりのPHP4によるWeb-DBシステム構築法を紹介しよう。 - Mac OS X+PHPでオールインワン環境(インストール編):Mac内にPHP4、5、6を同居させるコツ
PHP4の開発は終了したが、移行の問題は残されている。異なるバージョンのPHPをスムーズに切り替えるには? - @IT自分戦略研究所 資格辞典:PHP技術者認定試験
- 自分をプログラミング言語に例えると何?
2013年1月16日、エンジニアたちが集うトークライブイベント「TechLION vol.11」が開催された。今回のレポートでは、「自分をプログラミング言語に例える」というお題に答えた5人の技術者の回答をみていく。