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