PHP 5.3.9RC1 Released for Testing
リリースされました。NEWSファイルを見ると、かなりの量のバグFIXがなされているようです。
順調に行けば、2週間後にRC2が出てくるようです。
大きな修正点として、is_a関数の挙動が挙げられています。autoload機能を使ってクラスをロードしている場合への対応と思われますが、PHP5.3.7以降挙動が変更されていたのですが、PHP5.3.9RC1ではデフォルトの挙動を元に戻したようです。
The first release candidates of 5.3.9 was just released for testing and can be downloaded here:http://downloads.php.net/johannes/php-5.3.9RC1.tar.bz2 (md5sum: 5e8564008606edfab6a81137c1daf354)
The windows binaries are available at: http://windows.php.net/qa/
This is the first step in the release process of this versions and goal is having a 2nd RC two weeks from now. Majority of the changes are of the "bug fix" variety.
ここで「デフォルトの挙動」と書いたのは第3引数が追加されたためで、第1引数にクラス名を文字列で指定するかどうかを設定できるようになっています。Zend/zend_builtin_functions.cで以下のように定義されています。
One important change is for bug #55475 [1] where PHP 5.3.7 changed the behavior of is_a(). 5.3.9 will revert the behavior. Please ensure that the release is solid and all things behave as expected! Please test this RC against your code base and report any problems you encounter or successful tests you've run.
static void is_a_impl(INTERNAL_FUNCTION_PARAMETERS, zend_bool only_subclass) { zval *obj; char *class_name; int class_name_len; zend_class_entry *instance_ce; zend_class_entry **ce; zend_bool allow_string = only_subclass; zend_bool retval; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zs|b", &obj, &class_name, &class_name_len, &allow_string) == FAILURE) { return; } /* allow_string - is_a default is no, is_subclass_of is yes. if it's allowed, then the autoloader will be called if the class does not exist. default behaviour is different, as 'is_a' usage is normally to test mixed return values */ if (allow_string && Z_TYPE_P(obj) == IS_STRING) { zend_class_entry **the_ce; if (zend_lookup_class(Z_STRVAL_P(obj), Z_STRLEN_P(obj), &the_ce TSRMLS_CC) == FAILURE) { RETURN_FALSE; } instance_ce = *the_ce; } else if (Z_TYPE_P(obj) == IS_OBJECT && HAS_CLASS_ENTRY(*obj)) { instance_ce = Z_OBJCE_P(obj); } else { RETURN_FALSE; } if (zend_lookup_class_ex(class_name, class_name_len, 0, &ce TSRMLS_CC) == FAILURE) { retval = 0; } else { if (only_subclass && instance_ce == *ce) { retval = 0; } else { retval = instanceof_function(instance_ce, *ce TSRMLS_CC); } } RETURN_BOOL(retval); } : /* {{{ proto bool is_subclass_of(mixed object_or_string, string class_name [, bool allow_string=true]) Returns true if the object has this class as one of its parents */ ZEND_FUNCTION(is_subclass_of) { is_a_impl(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1); } /* }}} */
実際にbuildして試してみました。まずA.class.phpとB.class.php。
<?php class A {}
<?php class B extends A {}
test.phpはこんな感じ。
<?php function __autoload($class_name) { echo "load class '{$class_name}'" . PHP_EOL; require_once "{$class_name}.class.php"; } function output($target, $result) { echo 'B is ' . ($result ? '' : 'not ') . $target . PHP_EOL; } /** * $objはオブジェクト */ $obj = new B(); output('A', is_a($obj, 'A')); output('A', is_a($obj, 'A', true)); output('A', is_a($obj, 'A', false)); output('B', is_a($obj, 'A')); output('B', is_a($obj, 'A', true)); output('B', is_a($obj, 'A', false)); /** * $objは文字列(オブジェクトではない) */ $obj = 'B'; output('A', is_a($obj, 'A')); output('A', is_a($obj, 'A', true)); output('A', is_a($obj, 'A', false)); output('B', is_a($obj, 'A')); output('B', is_a($obj, 'A', true)); output('B', is_a($obj, 'A', false));
これを実行すると、次のようになりました。
$ ./sapi/cli/php test.php load class 'B' load class 'A' B is A B is A B is A B is B B is B B is B B is not A B is A B is not A B is not B B is B B is not B $
第1引数がオブジェクトの場合は特に問題ありませんが、クラス名を文字列で指定し、かつ、第3引数の値によって挙動が変わることが確認できました。
フレームワークやライブラリを作ってる人は注意が必要かもしれません。