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