前回に引き続き、
特に記述がない場合、
定義済みクラス
モジュールをロードするとクラスが定義される場合があるので、
C:\xampp\php\php4>phpcli.exe -r "print_r(get_declared_classes());" Array ( [0] => stdClass [1] => __PHP_Incomplete_Class [2] => Directory [3] => COM [4] => VARIANT [5] => swfshape [6] => swffill 以下省略
C:\xampp\php>php.exe -r "print_r(get_declared_classes());" Array ( [0] => stdClass [1] => Exception [2] => ErrorException [3] => COMPersistHelper [4] => com_exception [5] => com_safearray_proxy [6] => variant [7] => com [8] => dotnet [9] => ReflectionException [10] => Reflection [11] => ReflectionFunctionAbstract [12] => ReflectionFunction [13] => ReflectionParameter [14] => ReflectionMethod [15] => ReflectionClass [16] => ReflectionObject [17] => ReflectionProperty [18] => ReflectionExtension [19] => DateTime [20] => DateTimeZone [21] => LibXMLError [22] => __PHP_Incomplete_Class [23] => php_user_filter 以下省略
ここでは省略していますが、
PHP5からはInterfaceもサポートしています。このためInterfaceとして定義された名前もクラス名として利用できません。
C:\xampp\php>php.exe -r "print_r(get_declared_interfaces());" Array ( [0] => Traversable [1] => IteratorAggregate [2] => Iterator [3] => ArrayAccess [4] => Serializable [5] => Reflector [6] => RecursiveIterator [7] => OuterIterator [8] => Countable [9] => SeekableIterator [10] => SplObserver [11] => SplSubject )
PHP5のデフォルトの定義済みクラスで、
<?php
class DateTime{}
$obj = new DateTime;
?>
Fatal error: Cannot redeclare class DateTime in C:\xampp\php\- on line 2
どのクラス/
クラス/メソッド名の取得
クラス名を返すget_
<?php
class ClassName {}
$obj = new ClassName;
echo get_class($obj);
?>
ClassName
classname
PHP4用のコードをPHP5で動作させるには
strtolower(get_class($obj))
と大文字を小文字に変換します。
PHPが自動的に設定する__
インスタンスとクラス名の比較
PHP4にはインスタンスがどのようなクラスから生成されているか確認するis_
<?php
class foo {}
class bar extends foo {}
$obj = new bar;
if (is_a($obj, 'foo')) {
echo '$obj is "foo"'; ←$objはbarクラスなので実行されない
}
if (is_subclass_of($obj, 'foo')) {
echo '$obj is subclass of "foo"'; ←$objはfooを継承しているbarクラスのオブジェクトなので実行される
}
?>
PHP5でもis_
<?php
class foo {}
class bar extends foo {}
$obj = new bar;
if ($obj instanceof foo) {
echo '$obj is "foo"'; ←実行される
}
if ($obj instanceof bar) {
echo '$obj is "bar"'; ←実行される
}
?>
get_
メソッド定義
PHP5からメソッドへのアクセスにpublic, protected, privateのアクセス制御が可能になりました。
<?php
class foo {
// fooだけがアクセス可能
private func1() {}
// fooとfooを継承しているクラスからアクセス可能
protected func2() {}
// どこからでもアクセス可能
public func3() {}
func4() {} ←省略するとpublic
}
?>
PHP5への移行だけであればコードの書き換えは必要ありません。エラーが発生することもありません。
プロパティ定義
PHP4からPHP5への移行の障害となるため、
<?php
class foo {
public $p;
// PHP5ではvarはpublicと同じ
var $v;
}
?>
PHP5への移行には書き換えの必要はありません。現在のPHP5ではエラーが発生することもありません。
空のオブジェクト
PHP4のオブジェクト変数はプロパティが定義されていない場合、
empty($object)
とするとTRUEが返ってきました。PHP5のオブジェクト変数はempty($object)で常にFALSEと評価されます。
<?php
class foo {}
$obj = new foo;
if (!$obj) {
echo 'PHP4 is used'; // PHP4の場合のみ実行される
}
?>
オブジェクトプロパティの有無を調べるにはget_
<?php
class foo {}
$obj = new foo;
if (!get_object_vars($obj)) {
echo 'Works for PHP4 and PHP5';
}
?>
最初の回で解説済みですが、
配列形式のプロパティアクセス
古いPHPではオブジェクト変数のプロパティは配列のようにアクセスできましたが、
<?php
class foo {
var $a = 1;
var $b = 2;
}
$obj = new foo;
var_dump( $obj['a'] );
?>
[yohgaki@dev php4-php5-migration]$ ./php4 object-array-syntax.php NULL
[yohgaki@dev php4-php5-migration]$ ./php5 object-array-syntax.php Fatal error: Cannot use object of type foo as array in /home/yohgaki/php4-php5-migration/object-array-syntax.php on line 9
オブジェクトの比較
PHP5からオブジェクト変数がハンドルで取り扱われるようになり、
<?php
class foo {}
class bar extends foo {}
$foo1 = new foo;
$foo2 = $foo1;
if ($foo1 == $foo2) {
echo '$foo1 == $foo2'; ←PHP4/PHP5共に実行
}
if ($foo1 === $foo2) {
echo '$foo1 === $foo2'; ←PHP4/PHP5共に実行
}
$foo1->var = 123; ←PHP4の場合、$foo1と$foo2は別の変数。PHP5は同じ変数。
if ($foo1 == $foo2) {
echo '$foo1 == $foo2'; ←PHP5のみ実行
}
if ($foo1 === $foo2) {
echo '$foo1 === $foo2'; ←PHP5のみ実行
}
?>
PHP4、
PHP5でPHP4と同じ動作にするには、
$foo2 = clone $foo1;
とすればよいように思えますが、
if ($foo1 === $foo2) {
echo '$foo1 === $foo2'; ←PHP4/PHP5共に実行
}
の部分の実行結果が異なってしまいます。cloneを利用すると$foo1と$foo2は別のオブジェクト変数になり、
PHP4のコードでオブジェクトが代入でコピーされることを前提に記述されているコードの場合、
次回以降で詳しく解説しますが、
クラスの結合
PHP4まではクラスとオブジェクトを結合させるaggregate関数がサポートされていましたが、
クラス定義は静的な定義のみ可能ですが、
<?php
class foo {}
$obj = new foo;
$obj->new_property = 123;
?>
インターフェースを利用する場合の定義順序
インターフェースはPHP5からの新しい機能なので、
PHP5からクラスAPIのインターフェースを定義するinterfaceが導入されました。interfaceとはどのようなメソッドを実装しなければならないか定義する機能で、
interfaceはメソッドの中身を定義できない抽象クラスのようなものに見えますが、
<?php
// インターフェースが定義されていないのでエラー
$bar = new bar;
interface foo{} // 空の定義
class bar implements foo {}
?>
Fatal error: Class 'bar' not found in /home/yohgaki/- on line 3
インターフェースを利用する場合、
<?php
interface foo{} // 空の定義
class bar implements foo {}
// インターフェース、それを利用するクラス共に
// 定義されてるので動作する
$bar = new bar;
?>
__toStringの呼び出し
PHP5からオブジェクト変数が文字列として利用された場合、
<?php
class foo {}
$obj = new foo;
echo $obj;
?>
[yohgaki@dev php4-php5-migration]$ ./php4 __toString.php Object
[yohgaki@dev php4-php5-migration]$ ./php5 __toString.php Catchable fatal error: Object of class foo could not be converted to string in /home/yohgaki/php4-php5-migration/__toString.php on line 4
まとめ
今回はオブジェクトの仕様変更で最も大きな変更であったオブジェクト変数のハンドル化や、
次回はモジュール関連の違いについて解説します。