commit
44fdc0b387
18 changed files with 577 additions and 6 deletions
@ -0,0 +1,52 @@ |
||||
--TEST-- |
||||
Reference-returning functions can forward dynamic and chained calls |
||||
--FILE-- |
||||
<?php |
||||
function &dynamic_source(): mixed |
||||
{ |
||||
static $value = 1; |
||||
return $value; |
||||
} |
||||
|
||||
function &dynamic_forward(string $function): mixed |
||||
{ |
||||
return $function(); |
||||
} |
||||
|
||||
class DynamicRefBox |
||||
{ |
||||
public int $value = 2; |
||||
|
||||
public function &getValue(): mixed |
||||
{ |
||||
return $this->value; |
||||
} |
||||
} |
||||
|
||||
class DynamicRefFactory |
||||
{ |
||||
public function create(): DynamicRefBox |
||||
{ |
||||
return new DynamicRefBox(); |
||||
} |
||||
|
||||
public function &forward(): mixed |
||||
{ |
||||
return $this->create()->getValue(); |
||||
} |
||||
} |
||||
|
||||
function main(): void |
||||
{ |
||||
$dynamic = &dynamic_forward('dynamic_source'); |
||||
$dynamic = 10; |
||||
var_dump(dynamic_source()); |
||||
|
||||
$factory = new DynamicRefFactory(); |
||||
$chained = &$factory->forward(); |
||||
var_dump($chained); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
int(10) |
||||
int(2) |
||||
@ -0,0 +1,34 @@ |
||||
--TEST-- |
||||
Function returning by reference can forward another by-reference call |
||||
--FILE-- |
||||
<?php |
||||
|
||||
function main() |
||||
{ |
||||
$value1 = test1(); |
||||
var_dump($value1); |
||||
$value2 = &test1(); |
||||
var_dump($value2); |
||||
$value2 = 0; |
||||
$value3 = test1(); |
||||
var_dump($value3); |
||||
} |
||||
|
||||
function &test1() |
||||
{ |
||||
return test2(); |
||||
} |
||||
|
||||
function &test2() |
||||
{ |
||||
global $value; |
||||
$value++; |
||||
return $value; |
||||
} |
||||
|
||||
// main(); |
||||
?> |
||||
--EXPECT-- |
||||
int(1) |
||||
int(2) |
||||
int(1) |
||||
@ -0,0 +1,33 @@ |
||||
--TEST-- |
||||
Method returning by reference can forward another by-reference method call |
||||
--FILE-- |
||||
<?php |
||||
class Test |
||||
{ |
||||
private $value = 1; |
||||
|
||||
public function &getValue() |
||||
{ |
||||
return $this->value; |
||||
} |
||||
|
||||
public function &getRefValue() |
||||
{ |
||||
return $this->getValue(); |
||||
} |
||||
} |
||||
|
||||
function main() |
||||
{ |
||||
$test = new Test; |
||||
var_dump($test->getRefValue()); |
||||
$ref = &$test->getRefValue(); |
||||
$ref = 2; |
||||
var_dump($test->getValue()); |
||||
} |
||||
|
||||
// main(); |
||||
?> |
||||
--EXPECT-- |
||||
int(1) |
||||
int(2) |
||||
@ -0,0 +1,33 @@ |
||||
--TEST-- |
||||
Static method returning by reference can forward another by-reference static call |
||||
--FILE-- |
||||
<?php |
||||
class Counter |
||||
{ |
||||
private static $value = 0; |
||||
|
||||
public static function &next() |
||||
{ |
||||
self::$value++; |
||||
return self::$value; |
||||
} |
||||
|
||||
public static function ¤t() |
||||
{ |
||||
return self::next(); |
||||
} |
||||
} |
||||
|
||||
function main() |
||||
{ |
||||
var_dump(Counter::current()); |
||||
$ref = &Counter::current(); |
||||
$ref = 10; |
||||
var_dump(Counter::next()); |
||||
} |
||||
|
||||
// main(); |
||||
?> |
||||
--EXPECT-- |
||||
int(1) |
||||
int(11) |
||||
@ -0,0 +1,39 @@ |
||||
--TEST-- |
||||
Reference-returning static method forwards a late-static-bound reference |
||||
--FILE-- |
||||
<?php |
||||
class RefLsbBase |
||||
{ |
||||
protected static int $value = 1; |
||||
|
||||
protected static function &valueRef(): mixed |
||||
{ |
||||
return static::$value; |
||||
} |
||||
|
||||
public static function &forward(): mixed |
||||
{ |
||||
return static::valueRef(); |
||||
} |
||||
|
||||
public static function value(): int |
||||
{ |
||||
return static::$value; |
||||
} |
||||
} |
||||
|
||||
class RefLsbChild extends RefLsbBase |
||||
{ |
||||
protected static int $value = 2; |
||||
} |
||||
|
||||
function main(): void |
||||
{ |
||||
$value = &RefLsbChild::forward(); |
||||
$value = 20; |
||||
var_dump(RefLsbChild::value(), RefLsbBase::value()); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
int(20) |
||||
int(1) |
||||
@ -0,0 +1,44 @@ |
||||
--TEST-- |
||||
Static method calls (self / static / class name / parent) with by-reference args |
||||
--FILE-- |
||||
<?php |
||||
|
||||
class P |
||||
{ |
||||
public static function test(?string &$value): void |
||||
{ |
||||
$value = 'test'; |
||||
} |
||||
} |
||||
|
||||
class TestClass extends P |
||||
{ |
||||
public static function abc() |
||||
{ |
||||
self::test($v1); |
||||
var_dump($v1); |
||||
static::test($v2); |
||||
var_dump($v2); |
||||
TestClass::test($v3); |
||||
var_dump($v3); |
||||
parent::test($v4); |
||||
var_dump($v4); |
||||
static::test(value: $v5); |
||||
var_dump($v5); |
||||
parent::test(value: $v6); |
||||
var_dump($v6); |
||||
} |
||||
} |
||||
|
||||
function main() |
||||
{ |
||||
TestClass::abc(); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
string(4) "test" |
||||
string(4) "test" |
||||
string(4) "test" |
||||
string(4) "test" |
||||
string(4) "test" |
||||
string(4) "test" |
||||
@ -0,0 +1,38 @@ |
||||
--TEST-- |
||||
Static method call passing an undefined variable by reference (late static binding) |
||||
--FILE-- |
||||
<?php |
||||
|
||||
class Test |
||||
{ |
||||
public static function getName(?string &$name) |
||||
{ |
||||
$name = 'test'; |
||||
} |
||||
|
||||
public static function run() |
||||
{ |
||||
// $fileName is undefined; passing it by reference must auto-create it |
||||
// instead of raising an "Undefined variable" fatal error. |
||||
static::getName($fileName); |
||||
var_dump($fileName); |
||||
Test2::dump($fileName); |
||||
} |
||||
} |
||||
|
||||
class Test2 |
||||
{ |
||||
public static function dump(?string $value) |
||||
{ |
||||
var_dump($value); |
||||
} |
||||
} |
||||
|
||||
function main() |
||||
{ |
||||
Test::run(); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
string(4) "test" |
||||
string(4) "test" |
||||
@ -0,0 +1,34 @@ |
||||
--TEST-- |
||||
Assign by reference to late-static-bound property resolves to called class |
||||
--FILE-- |
||||
<?php |
||||
use native_types; |
||||
|
||||
class Base { |
||||
protected static int $value = 1; |
||||
|
||||
public static function bump(): void { |
||||
$ref = &static::$value; |
||||
$ref = 99; |
||||
} |
||||
|
||||
public static function show(): void { |
||||
var_dump(static::$value); |
||||
} |
||||
} |
||||
|
||||
class Child extends Base { |
||||
protected static int $value = 2; |
||||
} |
||||
|
||||
function main(): void { |
||||
Base::show(); |
||||
Child::bump(); |
||||
Child::show(); |
||||
Base::show(); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
int(1) |
||||
int(99) |
||||
int(1) |
||||
@ -0,0 +1,41 @@ |
||||
--TEST-- |
||||
Assign by reference to native typed static property (self / static / class name) |
||||
--FILE-- |
||||
<?php |
||||
use native_types; |
||||
|
||||
class Test |
||||
{ |
||||
private static int $value = 123; |
||||
|
||||
public static function abc(): void |
||||
{ |
||||
$a = &self::$value; |
||||
var_dump($a); |
||||
$a = 456; |
||||
var_dump(self::$value); |
||||
|
||||
$b = &static::$value; |
||||
var_dump($b); |
||||
$b = 789; |
||||
var_dump(static::$value); |
||||
|
||||
$c = &Test::$value; |
||||
var_dump($c); |
||||
$c = 1000; |
||||
var_dump(Test::$value); |
||||
} |
||||
} |
||||
|
||||
function main(): void |
||||
{ |
||||
Test::abc(); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
int(123) |
||||
int(456) |
||||
int(456) |
||||
int(789) |
||||
int(789) |
||||
int(1000) |
||||
@ -0,0 +1,36 @@ |
||||
--TEST-- |
||||
Assign by reference to parent static property (parent::$value) |
||||
--FILE-- |
||||
<?php |
||||
|
||||
class Base |
||||
{ |
||||
public static $value = 1; |
||||
} |
||||
|
||||
class Child extends Base |
||||
{ |
||||
public static function run() |
||||
{ |
||||
$ref = &parent::$value; |
||||
var_dump(parent::$value); |
||||
var_dump(Child::$value); |
||||
$ref = 999; |
||||
var_dump(parent::$value); |
||||
var_dump(Child::$value); |
||||
var_dump(Base::$value); |
||||
} |
||||
} |
||||
|
||||
function main() |
||||
{ |
||||
Child::run(); |
||||
} |
||||
|
||||
?> |
||||
--EXPECT-- |
||||
int(1) |
||||
int(1) |
||||
int(999) |
||||
int(999) |
||||
int(999) |
||||
@ -0,0 +1,25 @@ |
||||
--TEST-- |
||||
Reference to a typed static property preserves its type constraint |
||||
--FILE-- |
||||
<?php |
||||
use native_types; |
||||
|
||||
class TypedStaticReference |
||||
{ |
||||
public static int $value = 1; |
||||
} |
||||
|
||||
function main(): void |
||||
{ |
||||
$reference = &TypedStaticReference::$value; |
||||
try { |
||||
$reference = 'invalid'; |
||||
} catch (TypeError $error) { |
||||
echo "TypeError\n"; |
||||
} |
||||
var_dump(TypedStaticReference::$value); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
TypeError |
||||
int(1) |
||||
@ -0,0 +1,40 @@ |
||||
--TEST-- |
||||
Assign by reference to static property (self / static / class name) |
||||
--FILE-- |
||||
<?php |
||||
|
||||
class Test |
||||
{ |
||||
private static $value = 123; |
||||
|
||||
public static function abc(): void |
||||
{ |
||||
$a = &self::$value; |
||||
var_dump($a); |
||||
$a = 456; |
||||
var_dump(self::$value); |
||||
|
||||
$b = &static::$value; |
||||
var_dump($b); |
||||
$b = 789; |
||||
var_dump(static::$value); |
||||
|
||||
$c = &Test::$value; |
||||
var_dump($c); |
||||
$c = 1000; |
||||
var_dump(Test::$value); |
||||
} |
||||
} |
||||
|
||||
function main(): void |
||||
{ |
||||
Test::abc(); |
||||
} |
||||
?> |
||||
--EXPECT-- |
||||
int(123) |
||||
int(456) |
||||
int(456) |
||||
int(789) |
||||
int(789) |
||||
int(1000) |
||||
Loading…
Reference in new issue