- 实现了 NullsafePropertyFetch 和 NullsafeMethodCall 的解析支持 - 添加了 parseNullsafePropertyFetch 和 parseNullsafeMethodCall 方法 - 实现了 nullsafe 表达式的完整解析逻辑,包括属性和方法调用链式访问 - 更新了 PropertyDef 类以支持可空类型标记 - 修改了 getNativeMethod 和 findNativeMethod 方法参数类型为 CallLike - 添加了完整的测试用例覆盖 nullsafe 操作符的各种使用场景pull/1/head
parent
f12ceb1713
commit
dd46d6fa5f
6 changed files with 238 additions and 5 deletions
@ -0,0 +1,21 @@ |
|||||||
|
--TEST-- |
||||||
|
Nullsafe operator - method and property access |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
class User { |
||||||
|
public function getName(): string { |
||||||
|
return 'Alice'; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function main() { |
||||||
|
$user1 = null; |
||||||
|
var_dump($user1?->getName()); |
||||||
|
$user2 = new User(); |
||||||
|
var_dump($user2?->getName()); |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
NULL |
||||||
|
string(5) "Alice" |
||||||
|
|
||||||
@ -0,0 +1,89 @@ |
|||||||
|
--TEST-- |
||||||
|
Nullsafe operator - method and property access |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
class Customer { |
||||||
|
public function __construct( |
||||||
|
public ?Address $address = null, |
||||||
|
public string $name = "John" |
||||||
|
) {} |
||||||
|
|
||||||
|
public function getCountry(): ?string { |
||||||
|
return $this->address?->country ?? 'Unknown'; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class Address { |
||||||
|
public function __construct( |
||||||
|
public string $street = "Main St", |
||||||
|
public string $city = "NYC", |
||||||
|
public string $country = "USA" |
||||||
|
) {} |
||||||
|
|
||||||
|
public function getFullAddress(): string { |
||||||
|
return "{$this->street}, {$this->city}"; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// Test 6: Nullsafe with method returning object |
||||||
|
class ChainTest { |
||||||
|
public ?Child $child = null; |
||||||
|
|
||||||
|
public function getChild(): ?Child { |
||||||
|
return $this->child; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class Child { |
||||||
|
public string $name = "Alice"; |
||||||
|
|
||||||
|
public function getName(): string { |
||||||
|
return $this->name; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function main() { |
||||||
|
// Test 1: Nullsafe method call on non-null object |
||||||
|
$customer1 = new Customer(new Address("5th Avenue", "New York", "USA")); |
||||||
|
echo $customer1->address?->getFullAddress() . "\n"; |
||||||
|
|
||||||
|
// Test 2: Nullsafe method call on null object |
||||||
|
$customer2 = new Customer(null); |
||||||
|
var_dump($customer2->address?->getFullAddress()); |
||||||
|
|
||||||
|
// Test 3: Nullsafe property access on non-null object |
||||||
|
echo $customer1->address?->city . "\n"; |
||||||
|
|
||||||
|
// Test 4: Nullsafe property access on null object |
||||||
|
var_dump($customer2->address?->city); |
||||||
|
|
||||||
|
// Test 5: Chained nullsafe calls |
||||||
|
echo strtoupper($customer1?->address?->getFullAddress()); |
||||||
|
|
||||||
|
$test = new ChainTest(); |
||||||
|
$test->child = new Child(); |
||||||
|
|
||||||
|
// Test 7: Chained nullsafe method calls |
||||||
|
echo $test->getChild()?->getName() . "\n"; |
||||||
|
|
||||||
|
// Test 8: Chained nullsafe with null in middle |
||||||
|
$test2 = new ChainTest(); |
||||||
|
var_dump($test2->getChild()?->getName()); |
||||||
|
|
||||||
|
// Test 9: Nullsafe property access in expression |
||||||
|
$value = $customer1->address?->street ?? 'No street'; |
||||||
|
echo $value . "\n"; |
||||||
|
|
||||||
|
// Test 10: Multiple nullsafe in same expression |
||||||
|
echo ($customer1->address?->city ?? 'Unknown') . ", " . ($customer1->address?->country ?? 'Unknown') . "\n"; |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
5th Avenue, New York |
||||||
|
NULL |
||||||
|
New York |
||||||
|
NULL |
||||||
|
5TH AVENUE, NEW YORKAlice |
||||||
|
NULL |
||||||
|
5th Avenue |
||||||
|
New York, USA |
||||||
@ -0,0 +1,19 @@ |
|||||||
|
--TEST-- |
||||||
|
Nullsafe operator - method and property access |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
class User { |
||||||
|
public ?stdClass $prop = null; |
||||||
|
} |
||||||
|
|
||||||
|
function main() { |
||||||
|
$user = new User(); |
||||||
|
var_dump($user?->prop?->data); |
||||||
|
$user->prop = new stdClass(); |
||||||
|
$user->prop->data = 'hello'; |
||||||
|
var_dump($user?->prop?->data); |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
NULL |
||||||
|
string(5) "hello" |
||||||
@ -0,0 +1,28 @@ |
|||||||
|
--TEST-- |
||||||
|
Nullsafe operator - method and property access |
||||||
|
--FILE-- |
||||||
|
<?php |
||||||
|
class User1 { |
||||||
|
public function getName(): string { |
||||||
|
return 'Alice'; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
class User2 { |
||||||
|
public ?User1 $user = null; |
||||||
|
public function getUser() { |
||||||
|
return $this->user; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
function main() { |
||||||
|
$user = new User2(); |
||||||
|
var_dump($user?->getUser()?->getName()); |
||||||
|
|
||||||
|
$user->user = new User1(); |
||||||
|
var_dump($user?->getUser()?->getName()); |
||||||
|
} |
||||||
|
?> |
||||||
|
--EXPECT-- |
||||||
|
NULL |
||||||
|
string(5) "Alice" |
||||||
Loading…
Reference in new issue