Restrict array_key_exists optimization to integer and string keys (#130)
parent
f9a843e11c
commit
88ba4780c9
4 changed files with 151 additions and 0 deletions
@ -0,0 +1,23 @@ |
||||
<?php |
||||
/** |
||||
* This file is part of TypePHP(AOT). |
||||
* |
||||
* @link https://www.swoole.com/aot/ |
||||
* @contact service@swoole.com |
||||
*/ |
||||
|
||||
namespace KeyExistsOptimization; |
||||
|
||||
function check(array $array, int $integer, string $string, mixed $mixed, bool $boolean, float $float): void |
||||
{ |
||||
array_key_exists($integer, $array); |
||||
array_key_exists($string, $array); |
||||
array_key_exists($mixed, $array); |
||||
array_key_exists($boolean, $array); |
||||
array_key_exists($float, $array); |
||||
array_key_exists(null, $array); |
||||
array_key_exists([], $array); |
||||
array_key_exists(new \stdClass(), $array); |
||||
key_exists($mixed, $array); |
||||
$array->keyExists($mixed); |
||||
} |
||||
@ -0,0 +1,33 @@ |
||||
<?php |
||||
/** |
||||
* This file is part of TypePHP(AOT). |
||||
* |
||||
* @link https://www.swoole.com/aot/ |
||||
* @contact service@swoole.com |
||||
*/ |
||||
|
||||
use TypePhp\CompilerTest; |
||||
|
||||
/** |
||||
* @internal |
||||
* @coversNothing |
||||
*/ |
||||
final class ArrayKeyExistsOptimizationTest extends BaseTest |
||||
{ |
||||
public function testOnlyIntegerAndStringKeysUseDirectLookup(): void |
||||
{ |
||||
global $translator; |
||||
|
||||
$compiler = CompilerTest::create(TYPEPHP_ROOT_PATH); |
||||
$translator = $compiler; |
||||
$source = TYPEPHP_ROOT_PATH . '/phpunit/code/array-key-exists-optimization.php'; |
||||
$compiler->addFiles([$source]); |
||||
$compiler->prepareFile($source); |
||||
$code = file_get_contents($compiler->convertFile($source)); |
||||
|
||||
self::assertIsString($code); |
||||
self::assertSame(2, substr_count($code, '.offsetExists(')); |
||||
self::assertSame(8, substr_count($code, 'php::call(')); |
||||
self::assertStringNotContainsString('php::fn::array_key_exists(', $code); |
||||
} |
||||
} |
||||
@ -0,0 +1,90 @@ |
||||
--TEST-- |
||||
array_key_exists preserves key conversion, diagnostics and invalid-key errors |
||||
--FILE-- |
||||
<?php |
||||
namespace KeyExistsKeys { |
||||
|
||||
function lookup(mixed $key, array $array): void |
||||
{ |
||||
try { |
||||
var_dump(array_key_exists($key, $array)); |
||||
} catch (\Throwable $error) { |
||||
echo get_class($error), "\n"; |
||||
} |
||||
} |
||||
|
||||
function run(): void |
||||
{ |
||||
$diagnostics = []; |
||||
set_error_handler(function (int $severity, string $message, string $file, int $line) use (&$diagnostics): bool { |
||||
$diagnostics[] = $severity; |
||||
return true; |
||||
}); |
||||
|
||||
lookup(false, [0 => null]); |
||||
lookup(false, ['' => true]); |
||||
lookup(true, [1 => null]); |
||||
lookup('1', [1 => null]); |
||||
lookup('01', [1 => null]); |
||||
var_dump(array_key_exists(1, [1 => null]), array_key_exists('1', [1 => null])); |
||||
var_dump(array_key_exists(false, [0 => null])); |
||||
|
||||
lookup(1.5, [1 => null]); |
||||
var_dump(array_key_exists(1.5, [1 => null])); |
||||
var_dump($diagnostics === [E_DEPRECATED, E_DEPRECATED]); |
||||
$diagnostics = []; |
||||
|
||||
lookup(null, ['' => null]); |
||||
var_dump(array_key_exists(null, ['' => null])); |
||||
var_dump(count($diagnostics) === (PHP_VERSION_ID >= 80500 ? 2 : 0)); |
||||
$diagnostics = []; |
||||
|
||||
$resource = fopen(__FILE__, 'r'); |
||||
lookup($resource, [(int) $resource => null]); |
||||
var_dump($diagnostics === [E_WARNING]); |
||||
fclose($resource); |
||||
$diagnostics = []; |
||||
|
||||
lookup([], ['Array' => null]); |
||||
lookup(new \stdClass(), []); |
||||
var_dump($diagnostics === []); |
||||
|
||||
$array = [0 => null]; |
||||
$key = \std::any(false); |
||||
var_dump(key_exists($key, $array), $array->keyExists($key)); |
||||
var_dump(array_key_exists(array: $array, key: $key)); |
||||
var_dump(array_key_exists(...[$key, $array])); |
||||
restore_error_handler(); |
||||
} |
||||
} |
||||
namespace { |
||||
function main(): void |
||||
{ |
||||
\KeyExistsKeys\run(); |
||||
} |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
bool(true) |
||||
bool(false) |
||||
bool(true) |
||||
bool(true) |
||||
bool(false) |
||||
bool(true) |
||||
bool(true) |
||||
bool(true) |
||||
bool(true) |
||||
bool(true) |
||||
bool(true) |
||||
bool(true) |
||||
bool(true) |
||||
bool(true) |
||||
bool(true) |
||||
bool(true) |
||||
TypeError |
||||
TypeError |
||||
bool(true) |
||||
bool(true) |
||||
bool(true) |
||||
bool(true) |
||||
bool(true) |
||||
Loading…
Reference in new issue