parent
d5f0a113e6
commit
de8fdaf464
57 changed files with 1287 additions and 16 deletions
@ -0,0 +1,10 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeArrayAccessIsset {} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$value = new NativeArrayAccessIsset(); |
||||||
|
var_dump(isset($value[0])); |
||||||
|
} |
||||||
@ -0,0 +1,10 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeArrayAccessUnset {} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$value = new NativeArrayAccessUnset(); |
||||||
|
unset($value[0]); |
||||||
|
} |
||||||
@ -0,0 +1,10 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeArrayAccessWrite {} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$value = new NativeArrayAccessWrite(); |
||||||
|
$value[0] = 1; |
||||||
|
} |
||||||
@ -0,0 +1,10 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeArrayAccessOperand {} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$value = new NativeArrayAccessOperand(); |
||||||
|
var_dump($value[0]); |
||||||
|
} |
||||||
@ -0,0 +1,11 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeArrayDimKey {} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$key = new NativeArrayDimKey(); |
||||||
|
$values = []; |
||||||
|
$values[$key] = 'value'; |
||||||
|
} |
||||||
@ -0,0 +1,10 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeArrayKey {} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$key = new NativeArrayKey(); |
||||||
|
$values = [$key => 'value']; |
||||||
|
} |
||||||
@ -0,0 +1,7 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeBoxProperty |
||||||
|
{ |
||||||
|
public Box $value; |
||||||
|
} |
||||||
@ -0,0 +1,18 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeCoalesceExpected {} |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeCoalesceWrong {} |
||||||
|
|
||||||
|
function maybeExpected(): ?NativeCoalesceExpected |
||||||
|
{ |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$value = maybeExpected(); |
||||||
|
$value ??= new NativeCoalesceWrong(); |
||||||
|
} |
||||||
@ -0,0 +1,19 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeCoalescePropertyExpected {} |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeCoalescePropertyWrong {} |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeCoalesceHolder |
||||||
|
{ |
||||||
|
public ?NativeCoalescePropertyExpected $value; |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$holder = new NativeCoalesceHolder(); |
||||||
|
$holder->value ??= new NativeCoalescePropertyWrong(); |
||||||
|
} |
||||||
@ -0,0 +1,10 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeCompoundOperand {} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$value = new NativeCompoundOperand(); |
||||||
|
$value += 1; |
||||||
|
} |
||||||
@ -0,0 +1,13 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeDynamicConstantTarget |
||||||
|
{ |
||||||
|
public const VALUE = 1; |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$target = new NativeDynamicConstantTarget(); |
||||||
|
var_dump($target::VALUE); |
||||||
|
} |
||||||
@ -0,0 +1,10 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeDynamicNewTarget {} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$target = new NativeDynamicNewTarget(); |
||||||
|
$value = new $target(); |
||||||
|
} |
||||||
@ -0,0 +1,13 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeDynamicStaticTarget |
||||||
|
{ |
||||||
|
public function method(): void {} |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$target = new NativeDynamicStaticTarget(); |
||||||
|
$target::method(); |
||||||
|
} |
||||||
@ -0,0 +1,14 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeForeachValue |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$value = new NativeForeachValue(); |
||||||
|
foreach ($value as $item) { |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
@ -0,0 +1,19 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeGeneratorFactoryValue |
||||||
|
{ |
||||||
|
public int $value = 1; |
||||||
|
} |
||||||
|
|
||||||
|
function createNativeGeneratorValue(): NativeGeneratorFactoryValue |
||||||
|
{ |
||||||
|
return new NativeGeneratorFactoryValue(); |
||||||
|
} |
||||||
|
|
||||||
|
function nativeGeneratorFactory(): iterable |
||||||
|
{ |
||||||
|
$value = createNativeGeneratorValue(); |
||||||
|
yield $value->value; |
||||||
|
} |
||||||
|
|
||||||
@ -0,0 +1,14 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeGeneratorLocal |
||||||
|
{ |
||||||
|
public int $value = 1; |
||||||
|
} |
||||||
|
|
||||||
|
function nativeGeneratorLocal(): iterable |
||||||
|
{ |
||||||
|
$value = new NativeGeneratorLocal(); |
||||||
|
yield $value->value; |
||||||
|
} |
||||||
|
|
||||||
@ -0,0 +1,11 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeGeneratorMethod |
||||||
|
{ |
||||||
|
public function values(): iterable |
||||||
|
{ |
||||||
|
yield 1; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
@ -0,0 +1,13 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeGeneratorParameter |
||||||
|
{ |
||||||
|
public int $value = 1; |
||||||
|
} |
||||||
|
|
||||||
|
function nativeGeneratorParameter(NativeGeneratorParameter $value): iterable |
||||||
|
{ |
||||||
|
yield $value->value; |
||||||
|
} |
||||||
|
|
||||||
@ -0,0 +1,17 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeGeneratorYieldValue |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
function createNativeGeneratorYieldValue(): NativeGeneratorYieldValue |
||||||
|
{ |
||||||
|
return new NativeGeneratorYieldValue(); |
||||||
|
} |
||||||
|
|
||||||
|
function nativeGeneratorYield(): iterable |
||||||
|
{ |
||||||
|
yield createNativeGeneratorYieldValue(); |
||||||
|
} |
||||||
|
|
||||||
@ -0,0 +1,10 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeIncrementOperand {} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$value = new NativeIncrementOperand(); |
||||||
|
$value++; |
||||||
|
} |
||||||
@ -0,0 +1,12 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeReflectionClassValue |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
new ReflectionClass(NativeReflectionClassValue::class); |
||||||
|
} |
||||||
|
|
||||||
@ -0,0 +1,18 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeReflectionMemberValue |
||||||
|
{ |
||||||
|
public int $value; |
||||||
|
|
||||||
|
public function read(): int |
||||||
|
{ |
||||||
|
return $this->value; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
new ReflectionMethod(NativeReflectionMemberValue::class, 'read'); |
||||||
|
} |
||||||
|
|
||||||
@ -0,0 +1,13 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeSwitchCase {} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$value = new NativeSwitchCase(); |
||||||
|
switch (1) { |
||||||
|
case $value: |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,13 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeSwitchOperand {} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$value = new NativeSwitchOperand(); |
||||||
|
switch ($value) { |
||||||
|
case null: |
||||||
|
break; |
||||||
|
} |
||||||
|
} |
||||||
@ -0,0 +1,13 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeThrownValue |
||||||
|
{ |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$value = new NativeThrownValue(); |
||||||
|
throw $value; |
||||||
|
} |
||||||
|
|
||||||
@ -0,0 +1,10 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeUnaryOperand {} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$value = new NativeUnaryOperand(); |
||||||
|
$result = -$value; |
||||||
|
} |
||||||
@ -0,0 +1,14 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeVariableMethod |
||||||
|
{ |
||||||
|
public function method(): void {} |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$value = new NativeVariableMethod(); |
||||||
|
$method = 'method'; |
||||||
|
$value->$method(); |
||||||
|
} |
||||||
@ -0,0 +1,14 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeVariableProperty |
||||||
|
{ |
||||||
|
public int $property = 1; |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$value = new NativeVariableProperty(); |
||||||
|
$property = 'property'; |
||||||
|
var_dump($value->$property); |
||||||
|
} |
||||||
@ -0,0 +1,22 @@ |
|||||||
|
--TEST-- |
||||||
|
Native class: exit converts through the native string method |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeExitValue |
||||||
|
{ |
||||||
|
public function toString(): string |
||||||
|
{ |
||||||
|
return 'native exit'; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
exit(new NativeExitValue()); |
||||||
|
} |
||||||
|
|
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
native exit |
||||||
@ -0,0 +1,43 @@ |
|||||||
|
--TEST-- |
||||||
|
Native class: root frames remain valid across non-LIFO Fiber suspension |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeFiberValue |
||||||
|
{ |
||||||
|
public string $name; |
||||||
|
|
||||||
|
public function __construct(string $name) |
||||||
|
{ |
||||||
|
$this->name = $name; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function suspendedNativeFrame(): void |
||||||
|
{ |
||||||
|
$value = new NativeFiberValue('suspended'); |
||||||
|
Fiber::suspend(); |
||||||
|
echo $value->name, "\n"; |
||||||
|
} |
||||||
|
|
||||||
|
function resumeFromNewerNativeFrame(Fiber $fiber): void |
||||||
|
{ |
||||||
|
$value = new NativeFiberValue('newer'); |
||||||
|
$fiber->resume(); |
||||||
|
echo $value->name, "\n"; |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$fiber = new Fiber(static function (): void { |
||||||
|
suspendedNativeFrame(); |
||||||
|
}); |
||||||
|
$fiber->start(); |
||||||
|
resumeFromNewerNativeFrame($fiber); |
||||||
|
} |
||||||
|
|
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
suspended |
||||||
|
newer |
||||||
@ -0,0 +1,40 @@ |
|||||||
|
--TEST-- |
||||||
|
Native class: request shutdown safely detaches roots owned by suspended Fibers |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeFiberShutdownValue |
||||||
|
{ |
||||||
|
public string $name; |
||||||
|
|
||||||
|
public function __construct(string $name) |
||||||
|
{ |
||||||
|
$this->name = $name; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function suspendUntilRequestShutdown(): void |
||||||
|
{ |
||||||
|
$value = new NativeFiberShutdownValue('alive'); |
||||||
|
Fiber::suspend(); |
||||||
|
|
||||||
|
// This frame intentionally remains suspended until request shutdown. |
||||||
|
echo $value->name, "\n"; |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
global $suspendedFiber; |
||||||
|
|
||||||
|
$suspendedFiber = new Fiber(static function (): void { |
||||||
|
suspendUntilRequestShutdown(); |
||||||
|
}); |
||||||
|
$suspendedFiber->start(); |
||||||
|
|
||||||
|
echo "suspended\n"; |
||||||
|
} |
||||||
|
|
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
suspended |
||||||
@ -0,0 +1,28 @@ |
|||||||
|
--TEST-- |
||||||
|
Native class: long-running allocation triggers automatic tracing collection |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeGcThresholdValue |
||||||
|
{ |
||||||
|
public function __destruct() |
||||||
|
{ |
||||||
|
global $nativeGcFinalized; |
||||||
|
$nativeGcFinalized++; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
global $nativeGcFinalized; |
||||||
|
$nativeGcFinalized = 0; |
||||||
|
for ($i = 0; $i < 300000; $i++) { |
||||||
|
$value = new NativeGcThresholdValue(); |
||||||
|
} |
||||||
|
var_dump($nativeGcFinalized > 0); |
||||||
|
} |
||||||
|
|
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
bool(true) |
||||||
@ -0,0 +1,4 @@ |
|||||||
|
<?php |
||||||
|
|
||||||
|
var_dump(isset($nativeValue)); |
||||||
|
|
||||||
@ -0,0 +1,19 @@ |
|||||||
|
--TEST-- |
||||||
|
Native class: include scope does not expose raw native pointers to ZendVM |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeIncludeScopeValue {} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$nativeValue = new NativeIncludeScopeValue(); |
||||||
|
include __DIR__ . '/include-native-scope.inc'; |
||||||
|
var_dump($nativeValue instanceof NativeIncludeScopeValue); |
||||||
|
} |
||||||
|
|
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
bool(false) |
||||||
|
bool(true) |
||||||
@ -0,0 +1,60 @@ |
|||||||
|
--TEST-- |
||||||
|
Native class: match compares object identity without entering ZendVM |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeMatchValue {} |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeMatchUnrelated {} |
||||||
|
|
||||||
|
function nativeMatchIdentity(NativeMatchValue $value): NativeMatchValue |
||||||
|
{ |
||||||
|
echo "subject\n"; |
||||||
|
return $value; |
||||||
|
} |
||||||
|
|
||||||
|
function unrelatedMatchValue(): NativeMatchUnrelated |
||||||
|
{ |
||||||
|
echo "unrelated\n"; |
||||||
|
return new NativeMatchUnrelated(); |
||||||
|
} |
||||||
|
|
||||||
|
function scalarMatchValue(): int |
||||||
|
{ |
||||||
|
echo "scalar\n"; |
||||||
|
return 42; |
||||||
|
} |
||||||
|
|
||||||
|
function choose(?NativeMatchValue $subject, NativeMatchValue $same, NativeMatchValue $other): string |
||||||
|
{ |
||||||
|
return match ($subject) { |
||||||
|
$other => 'other', |
||||||
|
$same => 'same', |
||||||
|
null => 'null', |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$value = new NativeMatchValue(); |
||||||
|
$other = new NativeMatchValue(); |
||||||
|
|
||||||
|
var_dump(choose($value, $value, $other)); |
||||||
|
var_dump(choose(null, $value, $other)); |
||||||
|
var_dump(match (nativeMatchIdentity($value)) { |
||||||
|
unrelatedMatchValue() => 'unrelated', |
||||||
|
scalarMatchValue() => 'scalar', |
||||||
|
$value => 'identity', |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
string(4) "same" |
||||||
|
string(4) "null" |
||||||
|
subject |
||||||
|
unrelated |
||||||
|
scalar |
||||||
|
string(8) "identity" |
||||||
@ -0,0 +1,46 @@ |
|||||||
|
--TEST-- |
||||||
|
Native class: strict identity never coerces raw pointers to PHP values |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
|
||||||
|
#[Native] |
||||||
|
class NativeStrictIdentity {} |
||||||
|
|
||||||
|
function nativeIdentityOperand(NativeStrictIdentity $value): NativeStrictIdentity |
||||||
|
{ |
||||||
|
echo "native\n"; |
||||||
|
return $value; |
||||||
|
} |
||||||
|
|
||||||
|
function zendIdentityOperand(): bool |
||||||
|
{ |
||||||
|
echo "zend\n"; |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
function main(): void |
||||||
|
{ |
||||||
|
$value = new NativeStrictIdentity(); |
||||||
|
$alias = $value; |
||||||
|
$other = new NativeStrictIdentity(); |
||||||
|
|
||||||
|
var_dump($value === $alias); |
||||||
|
var_dump($value === $other); |
||||||
|
var_dump($value === true); |
||||||
|
var_dump($value !== true); |
||||||
|
var_dump(nativeIdentityOperand($value) === zendIdentityOperand()); |
||||||
|
var_dump(zendIdentityOperand() === nativeIdentityOperand($value)); |
||||||
|
} |
||||||
|
|
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
bool(true) |
||||||
|
bool(false) |
||||||
|
bool(false) |
||||||
|
bool(true) |
||||||
|
native |
||||||
|
zend |
||||||
|
bool(false) |
||||||
|
zend |
||||||
|
native |
||||||
|
bool(false) |
||||||
Loading…
Reference in new issue