オブジェクト指向言語に生まれ変わるPHP5[後編]

PHP5の新機能とPHP4との互換性

小山 哲志

2003/5/27

現在開発中のPHP5は、オブジェクト指向機能が大幅に強化される。次世代PHPはどのような言語になるのか? ベータリリースを目前にひかえたPHP5の言語仕様を解説する(編集部)

 現在開発中のPHPバージョン5(以下PHP5)。オブジェクト指向機能の大幅な強化が主な改善点であり、巷ではリリースに関する声もちらほら聞かれるようになってきた。

 そこで、PHP5の開発経緯やその新機能について、ここでざっとまとめてみたいと思う。

 

 

 

 

 

PHP5のリリーススケジュール

 前編「ベータリリース目前!? PHP5の新機能」で「Zend社からのニュースレターによれば、間もなくベータリリースされるようだ」と書いたが、開発者内の議論でベータにはまだ時期尚早だという結論になり、近々のベータリリースはされないことになった。

 この辺りの動向に興味のある方は、news://news.php.net/でホストされているニュースグループのphp.version5.dev:372で始まるスレッドを参照してほしい。

 この件でPHP5のリリースケージュールはまた白紙に戻ったわけだが、その一方でZend Engine 2自体は着実に開発が進んでいる。PHP5のリリースは「早くて年末だろう」というのが現在の大方の予想である。

PHP5の新機能(クラス関係の続き)

 それでは早速、前編に引き続いてクラス関係で拡張された機能を見ていこう。

名前空間

 PHP5では、名前空間(namespace)がサポートされた。これにより、クラス、変数、定数、関数を名前空間内に押し込めることができる。

 PHP4の変数スコープは、グローバル、関数内、クラス内の3種類しかなかったので、よほど注意してコーディングしないと容易にグローバル空間を汚染してしまっていた。名前空間を使えばパッケージごとに変数空間を分離できるので、より安易に独自パッケージを作成できるようになるだろう。

 使用例は以下のとおり。

namespace This {
  class Hoge {
  }
  const aConstant = 'This Constant';
  function aFunction() {}
  var $aVariable = 'This Variable';
}

$obj = new This::Hoge;
echo This::aConstant . "<br>\n";
This::aFunction();
echo This::$aVariable . "<br>\n";

 名前空間内のリテラルにアクセスするには、

名前空間名::リテラル

と表記する。ただしPHP5の名前空間は、C++とは異なりネストできない。

クラス内定数

 キーワードconstを用いて、クラス、名前空間内に定数を定義できるようになった。この場合定数なのでリテラルの頭に「$」は必要ない。クラス内定数は、そのクラスの中では同名のグローバル定数より優先される。

 これに伴い「const」は予約語となったので、クラス名や関数名にconstを使っている場合は修正が必要となる。

<?php
define('constant_value', 'global constant');

class MyClass {
  const constant_value = 'class constant';

  function printConstant() {
    print constant_value;
  }
}

echo MyClass::constant_value . "<br>\n";
MyClass::printConstant();
?>

 この例では、MyClass::printConstant()は定数constant_valueをプリントするが、constant_valueはグローバル空間とクラス内の2カ所に存在する。その場合、MyClass内の定数constant_valueが優先され、「class constant」が表示される。

クラス変数

 クラス変数は、インスタンスを1つも作らない状態でも、きちんと指定した値で初期化されるようになった。アクセス方法は、

クラス名::$変数名

となる。

<?php
class Hoge {
  static $my_static = 5;
}

print Hoge::$my_static;
?>

統一コンストラクタ

 オブジェクトが生成される際、自動的に呼ばれるメソッドを「コンストラクタ」という。

 PHP4のコンストラクタは、クラス名と同名のメソッドだった。これはJavaやC++と同じ仕様なので、そちらに慣れている人には違和感がないのだが、子クラスから親クラスのコンストラクタを呼びたい場合、Javaでいうsuper()が存在しないPHPでは親クラスの名前をわざわざ書かなければならない。PHPでは親クラスのコンストラクタは自動的に呼ばれないので、そうしたケースは比較的多い。

 そこでPHP5では、__construct()という統一コンストラクタ名を採用した。クラス名にかかわらず、__construct()というメソッドがコンストラクタとして扱われる。

【注】
__constructの「__」は、「_」が2つ連続している。以下に登場する「__」も同様。

 またPHP4との互換性のため、クラス名と同名の従来のコンストラクタが存在すれば、そちらが優先して使用される。

<?php
class BaseClass {
  function __construct() {
    print "In BaseClass constructor\n";
  }
}

class SubClass extends BaseClass {
  function __construct() {
    parent::__construct();
    print "In SubClass constructor\n";
  }
}

$obj = new BaseClass();
$obj = new SubClass();
?>

デストラクタ

 コンストラクタとは逆に、オブジェクトが消滅するときに自動的に呼ばれるメソッドを「デストラクタ」という。

 PHP4ではデストラクタはサポートされておらず、register_shutdown_function()でPHPの実行終了時に呼び出される関数を登録することにより、疑似的に実現するしか方法がなかった。PHP5では正式にデストラクタがサポートされ、クラスごとにオブジェクトの消滅時の振る舞いを指定できるようになった。

 デストラクタは、__destructという名前のメソッドになる。オブジェクトの内部的な参照カウンタが0になると、__destruct()メソッドが呼び出され、その後でオブジェクトが保持しているメモリ領域が解放される。

<?php
class MyDestructableClass {
  function __construct() {
    print "In constructor\n";
    $this->name = 'MyDestructableClass';
  }

  function __destruct() {
    print 'Destroying ' . $this->name . "\n";
  }
}

$obj = new MyDestructableClass();
?>

 なお、コンストラクタがそうであるのと同様に、親クラスのデストラクタが自動的に呼び出されることはない。必要な場合は、

parent::__destruct();

と記述して、明示的に呼び出してやる必要がある。

アクセサ

 PHP4では、存在しないプロパティへアクセスが発生すると、自動的にそのプロパティを生成することで対応していた。例えば、

class Hoge {
}

$obj = new Hoge;
$obj->prop = "This is new property";

のように、存在しないプロパティに値を代入しようとすると、代入時点でそのプロパティが生成される。同様に、存在しないプロパティの参照も、(Warning付きではあるが)null値が代入された変数があるかのように振る舞い、決してエラーになることはない。

 PHP5ではこれに追加して、任意のプロパティへのアクセスを制御できる仕組みが導入された。クラスに__set()、__get()というメソッドが存在すると、上記の振る舞いの代わりにこれらのメソッドが呼び出される。例を見てみよう。

<?php
class Hoge {
  function __set($name, $value) {
    print "__set() is called with ($name, $value)\n";
    $this->$name = $value;
  }
}

$obj = new Hoge;

$obj->a = '123';
$obj->a = '456';
$obj->b = '789';
?>

 ここでは、__setメソッドは引数をプリントした後にそのままプロパティとして代入している。

$obj->a = '123';

で$obj->aに値を代入しているが、この時点ではプロパティaは存在しないので、代わりに__setメソッドが呼び出される。

__set() is called with (a, 123)

と表示されるはずだ。次に、

$obj->a = '456';

ともう一度$obj->aに代入している。今度は先ほどの代入でプロパティaが存在するので__setメソッドは呼び出されず、通常のプロパティ代入となる。

 さらに今度は、

$obj->b = '789';

として別のプロパティbに代入すると、aの1回目と同様に、

__set() is called with (b, 789)

と表示されるだろう。

 __getメソッドは、__setとは逆で、存在しないプロパティへの参照を上書きする。__setと__getを組み合わせると、プロパティへのアクセスのように見えて、実は全然違う場所に影響を与えるクラスを作成することができる。

<?php
class Hoge {
  public $properties;

  function __set($name, $value) {
    $this->properties[$name] = $value;
  }
  function __get($name) {
    return $this->properties[$name];
  }
}

$obj = new Hoge;

$obj->a = '123';
$obj->b = '456';
echo $obj->a;
echo $obj->b;

print_r($obj);
?>

 この例では、クラスHogeのすべてのプロパティアクセスを$propertiesという配列に押し込めている。これはオブジェクト直下のプロパティをあまり使わないだけで、何がうれしいのかよく分からない例だが、この保存先を例えばファイルやDBに変えてみたりするのも面白いだろう。一見オブジェクトに何げなくアクセスしているように見えて、実は裏ではたくさんのコードが動いているということが簡単に実現できる。

 __set、__getとは多少趣が違うが、__callという、存在しないメソッドを上書きするものも用意されている。オブジェクトのメソッドを以下のように呼んだとき、

$object->methodname();

もしそのクラスにmethodnameというメソッドが存在しなければ、通常ならば、

Fatal error: Call to undefined method Class::methodname()

というエラーになる。だが、__callというメソッドがそのクラスにある場合、代わりに__callが呼び出される。__callの引数は2つで、第1引数は呼び出されたメソッド名、第2引数は呼び出し時の引数を保持した配列だ。使い方はいろいろ考えられるが、例えば以下のようにほかのオブジェクトへ呼び出しを委譲するといったことができる。

<?php
class Proxy {
  private $object;

  function __call($name, $params) {
    if (isset($this->object)) {
      if (method_exists($this->object, $name)) {
      return call_user_func_array(array($this->object, $name), $params);
      }
      else {
      return "method not exists.";
      }
    }
  }
  function __construct($object) {
    $this->object = $object;
  }
}

class Hoge {
  function add($var1, $var2) {
    return $var1 + $var2;
  }
}

$p = new Proxy(new Hoge);

$result = $p->add(1, 2);
echo "result: $result<br>\n";

$result = $p->sub(5, 3);
echo "result: $result<br>\n";
?>

 
1/2

Index
PHP5の新機能とPHP4との互換性
Page1
PHP5のリリーススケジュール
PHP5の新機能(クラス関係の続き)
 名前空間
 クラス内定数
 クラス変数
 統一コンストラクタ
 デストラクタ
 アクセサ
  Page2
クラス以外の拡張機能
 引数が参照の場合のデフォルト値
 __autoload()
 例外処理
 そのほか
PHP4との互換性
まとめ

オブジェクト指向言語に生まれ変わるPHP5

 PHP関連記事
例外処理の実装を把握する
PHP5で広がる! 開発環境(1)
 PHP4のサポートが終了し、いよいよPHP5への移行を視野に入れる時期が来た。PHP5の機能を生かした開発のポイントを紹介
クライアントPCに言語環境を入れる理由
Mac OS X+PHPでオールインワン環境(準備編)
 Webアプリ開発者に人気のMac OS X。効率的な開発のために複数バージョンのPHPを実行する環境を構築してみよう
PHPに押し寄せるリスクと国際化の波
PHPカンファレンス2008レポート(前編)
 PHP4のサポートが完全に終了する。多くの新機能が投入されるPHP5.3へ移行か、国際化対応で開発が遅れるPHP6を待つか
PHPによる大規模商用サービスの裏側
PHPカンファレンス2008レポート(中編)
 企業のWebアプリケーション開発現場で利用されるPHP。開発現場の裏側にはさまざまなドラマが隠されている
PHPユーザーは本当にほかの言語を知らないのか?
PHPカンファレンス2008レポート(後編)
 PHPは本当にダメな言語なのだろうか。Perl、Ruby、Python、Java、JavaScriptの使い手が白熱した議論を行った
  Coding Edgeフォーラムフィード  2.01.00.91


Coding Edge フォーラム 新着記事
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

>

Coding Edge 記事ランキング

本日 月間