PHP の interface や implements ってご存知ですか ? 知っている前提で話を進めます。

それでは PHP の組込みインターフェイスをご存知ですか ?
この記事ではそれについて紹介します。

なお、PHP のバージョンは 5.3 以降を前提としています。 (多分、 5.2 でも動く)

PHP の組込みインターフェイスとは

PHP でインターフェイスを定義するには、 interface 宣言を記述する必要があります。
しかし、以下のようなインターフェイスは PHP に予め組込まれており、定義すること無しに利用できます。

普通 interface といえば、メソッドの定義を強制することで、クラスの再利用性を高めるために用いられていると思います。
上記の組込みのインターフェイスについても、もちろんそういった利点があります。

ですが、組込みインターフェイスには、通常のクラス定義ではあり得ない振る舞いをオブジェクトに持たせることができるものがあります。
要は 普通じゃないオブジェクトを作れる ということです。

配列っぽいオブジェクトをつくる

ここからは、PHP の組込みインターフェイスの便利さを知ってもらうために、配列っぽいオブジェクトの作り方を説明します。

さて、配列っぽいってどういうことでしょうか ?
配列、つまり PHP の array 型は、以下のような使い方ができますね。

以下では、array 型が持つこれらの機能を、オブジェクトに実装していきます。

(0) コンストラクタ

まずは、 array をプロパティとして持つ ArrayLike クラスを定義します。

<?php
class ArrayLike
{
    protected $_arr;

    public function __construct($arr = array())
    {
        $this->_arr = $arr;
    }
}

ArrayLike オブジェクトは以下のように生成します。

<?php
require_once 'ArrayLike.php';

$arrObj = new ArrayLike(array('foo', 'bar', 'baz'));

以下では省略しますが、 $arrObj はすべてこのように生成しているという前提でお読みください。

(1) 要素数を数える (Countable)

現状ではこうなります。

<?php
echo count($arrObj), PHP_EOL; // => 1

3 となって欲しいところですが、なりません。
オブジェクトに count() 関数を適用すると、通常は常に 1 となるようです。
(count 関数のマニュアルには「オブジェクトに含まれるプロパティの数を数える」となってますが間違いのようです)

そこで、 ArrayLike クラスに次のような変更を加えましょう。
最初に宣言したプロパティや定義したメソッドは省略します。

<?php
class ArrayLike implements Countable
{
    public function count()
    {
        return count($this->_arr);
    }
}

Countable というインターフェイスに定義されている count() メソッドを実装しました。
すると、 count() に対する ArrayLike オブジェクトの振る舞いはいかのようになります。

<?php
echo count($arrObj), PHP_EOL; // => 3

期待通りの値が返ってきました !
これで配列に一歩近づきましたね。

(2) 要素を 1 つ 1 つ列挙する (Iterator)

foreach 構文にオブジェクトを渡すと、通常は public なプロパティが列挙されます。
ArrayLike オブジェクトは public なプロパティを持たないので、 foreach は空振りします。
構文エラーではありませんが、やはり配列として期待する動作とは違います。

そこで、再び ArrayLike クラスに変更を加えます。
先ほどまでに実装している部分は省略しています。
実装するメソッド数がさっきより多いので、詳細は気にせず「Iterator インターフェイスのメソッドを実装した」ことだけ理解していただけで問題ありません。

<?php
class ArrayLike implements Countable, Iterator
{
    protected $_index;

    public function rewind()
    {
        $this->_index = 0;
    }

    public function key()
    {
        return $this->_index;
    }

    public function current()
    {
        return $this->_arr[$this->key()];
    }

    public function next()
    {
        $this->_index++;
    }

    public function valid()
    {
        return $this->_index < $this->count();
    }
}

すると、 foreach に対する ArrayLike オブジェクトの振る舞いは以下のようになります。

<?php
foreach ($arrObj as $key => $value) {
    echo "{$key}:{$value}", PHP_EOL;
}
// =>
//   0:foo
//   1:bar
//   2:baz

だいぶ配列に近づいてきましたね。

(3) 要素へ値の代入と取得 (ArrayAccess)

count や foreach のときと違い、オブジェクトに対して [] 演算子を使うと Fatal error となります。

<?php
$arrObj[1] = 'foo'; => PHP Fatal error:  Cannot use object of type ArrayLike as array in...

というわけで、さらに ArrayLike に手を加えます。
例によって、今までに実装したメソッドや宣言したプロパティは省略しています。

<php
class ArrayLike implements Countable, Iterator, ArrayAccess
{
    public function offsetSet($key, $value)
    {
        $this->_arr[$key] = $value;
    }

    public function offsetGet($key)
    {
        return $this->_arr[$key];
    }

    public function offsetExists($key)
    {
        return isset($this->_arr[$key]);
    }

    public function offsetUnset($key)
    {
        unset($this->_arr[$key]);
    }
}

さて、再び [] 演算子を使ってみましょう。

<?php
$arrObj[1] = 'foo';
echo $arrObj[1], PHP_EOL; // => foo

これはもうほとんど配列ですね。

完成

ここまでで実装してきたものをまとめると以下のようになります。

まとめ

PHP の組込みインターフェイスを使うと、普通のクラス定義ではありえない振る舞いをオブジェクトに持たせることができます。
また、言語組込みのインターフェイスなので、とりあえずこれに従っておけば、メソッドの命名で喧嘩せずに済むかもしれません。

See also

, ,

パーフェクト PHP

パーフェクト PHP

いきなり結論

少なくとも PHP 5.3 時代である現在、この本の登場をもって、これまでにあった有象無象の「PHP と MySQL でインタラクティブなホームページをつくろう !」的な本はその役割を終えました … と言えるぐらい網羅されているので、買いましょう。

この書籍のターゲット

購入前のイメージでは中級者以上向けかと思っていましたが、手に取って読んでみると、初心者も対象に含まれているようで、 PHP のインストールや、文法の概要についてもカバーされていました。

ある程度 PHP を使いこなしている人であれば、読み飛ばす箇所も結構あると思いますが、言語仕様の細かい部分で「これは知らなかった」という部分にも出会えます。
例えば、リファレンスカウントによるガベージコレクションの仕組みや、コピーオンライトによる最適化については、知らない人も結構いると思います。 (少なくとも、私は PHP でコピーオンライトが使われていると意識したことはありませんでした)

個人的には、エキスパートPythonプログラミング みたいに、「これを読めば PHP ハッカーになれる !」みたいなのを期待していましたが、そういうのは想定されいないようです。
その分敷居はやや低めなので、 PHP 入門以前の方も安心して楽しめます。

書いてあること

  • インストール方法
    Linux, Mac のパッケージマネージャによるインストールと、 Windows では XAMPP によるインストール方法が紹介されています。
  • 内部処理の概要
    レキサー、パーサー、オペコードについての簡単な説明。
  • 基本的な文法
    既に PHP が書ける人であれば読み飛ばせる。
  • PHP 5.3 以降の新しい機能
    名前空間、無名関数、クロージャ、クラスのオートローディングなどについてもしっかり詳解されています。
    業務ではまだ 5.2 以前の PHP を使っている、という人も覚えておきたい内容。
  • Web アプリケーションの作成
    フレームワークを作成して、それを基に Twitter ライクな Web アプリケーションを作成しています。
    フレームワーク自体は割とミニマムにまとまっているので、いわゆるフレームワークが何をしてくれるのか、というのを雑観するのにもいいと思います。
  • セキュリティ
    XSS, CSRF, SQL インジェクションをはじめとして、具体的な攻撃手法とその対策が紹介されています。
    全 PHP エンジニアが理解しておくべき内容。
  • やや高度な機能
    主に PHP5 以降のオブジェクト指向的な何かについて。
    マジックメソッド、標準インターフェイス、SPL、PDO、DateTime、JSON 等。
  • 雑多なテクニック
    いわゆるレシピ。

書いてないこと

  • 既存オープンソースフレームワーク解説
    symfony のシの字も、 Ethna のエの字もありません。
    著者の中にはそれらの関係者の方もいますが、意図的にトピックから外しているようです。
  • テスト駆動開発
    エキスパートPythonプログラミング みたいに、そこまで触れるというのもありだとは思いました。
    とはいえ、具体的なフレームワークの紹介は行わない方針のようなので、そういった意味でもしょうが無いですねこれは。
  • PEAR/PECL パッケージの作り方
    それぞれの概要については触れられるものの、パッケージの作り方については特に言及されていません。
    Openpear についての宣伝があっても誰も怒らないとは思うのですが …
  • オブジェクト指向それ自体の説明
    「PHP におけるオブジェクト指向」には触れられていますが、それ以上については専門書を読みましょう。
  • コーディング規約
    個人的にはモダン PHP を語る上では、結構重要なトピックだと思っています。

結構斜め読みで読み終えているので、「これについてはちゃんと書かれていたよ !」というのがあればご指摘いただければ幸いです。

初心者にオススメしたい活用法

PHP 初心者、もしくはこれから入門、という方に「こういう勉強法はどうでしょう ?」ということでオススメします。
といっても私自信がこれを実践したわけではないので、あまり偉そうには言えませんが …
あくまでも「いち提案」として。

  1. Part 1 を読みながら、ローカルに開発環境を構築する
  2. Part 3 の実践 Web アプリケーション開発をひたすら写経
    Part 2 の言語仕様をいきなり読むのは大変なので、じっくり読むのは何となくで PHP が書けるようになってから
  3. Part 4 の PHP セキュリティについての読書会を行う
    業務で PHP を使っているのであれば、是非チームで共有しましょう
  4. Part 5 のテクニカルな PHP の活用、 Part 6 の PHP レシピはすき間時間等に読んでおき、「こんなこともできるのかー」程度に頭にいれておく

Part 4 の読書会は、私も自社内でやってみたいところです。

その他に読んでおきたい PHP 本

パーフェクト PHP が登場してもなお、その存在価値を失わないと思われる PHP 本を紹介します。
個別のフレームワークの解説本等は外し、より多くの PHP エンジニアに読まれるべきものを選んでいます。