オブジェクトに対するarray_key_exists関数呼び出しの代替策について
array_key_exists関数の第二パラメータにオブジェクトを渡すとエラーになるようになってから久しいが、PHP 5.4.16で動くシステムを最低でもPHP 7.3以降に上げなければならなくなったためにぶつかった壁の調査。
以下のようなコードをPHP 5.6.40/7.4.29/8.1.6で実行してみる。
- Main.php
<?php printf("%s\n", PHP_VERSION); ini_set('display_errors', '1'); ini_set('error_reporting', E_ALL); class A { } $obj = new A(); $ary = array(); $k = 'noExistence'; printf("%-12s: %d %d\n", $k, array_key_exists($k, $ary), array_key_exists($k, $obj));
$ php56 Main.php 5.6.40 noExistence : 0 0 $
$ php74 Main.php 7.4.29 PHP Deprecated: array_key_exists(): Using array_key_exists() on objects is deprecated. Use isset() or property_exists() instead in /home/hhelibex/blog/2022-0518-01/Main.php on line 18 Deprecated: array_key_exists(): Using array_key_exists() on objects is deprecated. Use isset() or property_exists() instead in /home/hhelibex/blog/2022-0518-01/Main.php on line 18 noExistence : 0 0 $
$ php81 Main.php 8.1.6 PHP Fatal error: Uncaught TypeError: array_key_exists(): Argument #2 ($array) must be of type array, A given in /home/hhelibex/blog/2022-0518-01/Main.php:18 Stack trace: #0 {main} thrown in /home/hhelibex/blog/2022-0518-01/Main.php on line 18 Fatal error: Uncaught TypeError: array_key_exists(): Argument #2 ($array) must be of type array, A given in /home/hhelibex/blog/2022-0518-01/Main.php:18 Stack trace: #0 {main} thrown in /home/hhelibex/blog/2022-0518-01/Main.php on line 18 $
確かにエラーになる。 さて、PHP 7.4.29での実行結果に「Use isset() or property_exists() instead」とあるので、その辺を検証してみる。
- Test.php
<?php printf("%s\n", PHP_VERSION); ini_set('display_errors', '1'); ini_set('error_reporting', E_ALL); class A { } $base = array( 'isNull' => null, 'isZero' => 0, 'isOne' => 1, 'isStr0' => '0', 'isEmptyStr' => '', 'isStrHoge' => 'hoge', ); $obj = new A(); foreach ($base as $k => $v) { $obj->$k = $v; } $ary = $base; var_dump($obj, $ary); foreach ($base as $k => $v) { printf("%-12s: %d %d %d %d\n", $k, array_key_exists($k, $ary), property_exists($obj, $k), isset($ary[$k]), isset($obj->$k)); } $k = 'noExistence'; printf("%-12s: %d %d %d %d\n", $k, array_key_exists($k, $ary), property_exists($obj, $k), isset($ary[$k]), isset($obj->$k));
これを同様に実行してみると、以下のようになる。
$ php56 Test.php 5.6.40 object(A)#1 (6) { ["isNull"]=> NULL ["isZero"]=> int(0) ["isOne"]=> int(1) ["isStr0"]=> string(1) "0" ["isEmptyStr"]=> string(0) "" ["isStrHoge"]=> string(4) "hoge" } array(6) { ["isNull"]=> NULL ["isZero"]=> int(0) ["isOne"]=> int(1) ["isStr0"]=> string(1) "0" ["isEmptyStr"]=> string(0) "" ["isStrHoge"]=> string(4) "hoge" } isNull : 1 1 0 0 isZero : 1 1 1 1 isOne : 1 1 1 1 isStr0 : 1 1 1 1 isEmptyStr : 1 1 1 1 isStrHoge : 1 1 1 1 noExistence : 0 0 0 0 $
$ php74 Test.php 7.4.29 object(A)#1 (6) { ["isNull"]=> NULL ["isZero"]=> int(0) ["isOne"]=> int(1) ["isStr0"]=> string(1) "0" ["isEmptyStr"]=> string(0) "" ["isStrHoge"]=> string(4) "hoge" } array(6) { ["isNull"]=> NULL ["isZero"]=> int(0) ["isOne"]=> int(1) ["isStr0"]=> string(1) "0" ["isEmptyStr"]=> string(0) "" ["isStrHoge"]=> string(4) "hoge" } isNull : 1 1 0 0 isZero : 1 1 1 1 isOne : 1 1 1 1 isStr0 : 1 1 1 1 isEmptyStr : 1 1 1 1 isStrHoge : 1 1 1 1 noExistence : 0 0 0 0 $
$ php81 Test.php 8.1.6 object(A)#1 (6) { ["isNull"]=> NULL ["isZero"]=> int(0) ["isOne"]=> int(1) ["isStr0"]=> string(1) "0" ["isEmptyStr"]=> string(0) "" ["isStrHoge"]=> string(4) "hoge" } array(6) { ["isNull"]=> NULL ["isZero"]=> int(0) ["isOne"]=> int(1) ["isStr0"]=> string(1) "0" ["isEmptyStr"]=> string(0) "" ["isStrHoge"]=> string(4) "hoge" } isNull : 1 1 0 0 isZero : 1 1 1 1 isOne : 1 1 1 1 isStr0 : 1 1 1 1 isEmptyStr : 1 1 1 1 isStrHoge : 1 1 1 1 noExistence : 0 0 0 0 $
いずれも「nullが代入されたpropertyが存在する」時にisset()とproperty_exists()の挙動が異なる。
すなわち、厳密には、オブジェクトに対するarray_key_exists関数の呼び出しはproperty_exists関数でしか代用できない。