Skip to content

Commit

Permalink
Implement nullsafe ?-> operator
Browse files Browse the repository at this point in the history
  • Loading branch information
iluuu1994 committed Jun 3, 2020
1 parent 0badfc0 commit f5785fd
Show file tree
Hide file tree
Showing 25 changed files with 1,328 additions and 523 deletions.
98 changes: 98 additions & 0 deletions Zend/tests/nullsafe_method_call/001.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
--TEST--
Test basic nullsafe method calls
--FILE--
<?php

class Foo {
function null() {
var_dump('Foo::null()');
return null;
}

function self() {
var_dump('Foo::self()');
return $this;
}
}

var_dump(null?->bar());
var_dump(null?->bar(var_dump('Not executed')));
var_dump(null?->bar()->baz());
var_dump(null?->bar()->baz(var_dump('Not executed')));
var_dump(null?->bar()->baz);
var_dump(null?->bar()::$baz);
var_dump(null?->bar()::baz());

$foo = new Foo();
var_dump($foo->null()?->bar());
var_dump($foo->null()?->bar(var_dump('Not executed')));
var_dump($foo->null()?->bar()->baz());
var_dump($foo->null()?->bar()->baz(var_dump('Not executed')));
var_dump($foo->null()?->bar()->baz);
var_dump($foo->null()?->bar()::$baz);
var_dump($foo->null()?->bar()::baz());

$foo = new Foo();
var_dump($foo?->self()->null()?->bar());
var_dump($foo?->self()->null()?->bar(var_dump('Not executed')));
var_dump($foo?->self()->null()?->bar()->baz());
var_dump($foo?->self()->null()?->bar()->baz(var_dump('Not executed')));
var_dump($foo?->self()->null()?->bar()->baz);
var_dump($foo?->self()->null()?->bar()::$baz);
var_dump($foo?->self()->null()?->bar()::baz());

var_dump($foo->self(null?->bar())->null());
try {
var_dump($foo?->self()[null?->bar()]);
} catch (Throwable $e) {
var_dump($e->getMessage());
}

--EXPECT--
NULL
NULL
NULL
NULL
NULL
NULL
NULL
string(11) "Foo::null()"
NULL
string(11) "Foo::null()"
NULL
string(11) "Foo::null()"
NULL
string(11) "Foo::null()"
NULL
string(11) "Foo::null()"
NULL
string(11) "Foo::null()"
NULL
string(11) "Foo::null()"
NULL
string(11) "Foo::self()"
string(11) "Foo::null()"
NULL
string(11) "Foo::self()"
string(11) "Foo::null()"
NULL
string(11) "Foo::self()"
string(11) "Foo::null()"
NULL
string(11) "Foo::self()"
string(11) "Foo::null()"
NULL
string(11) "Foo::self()"
string(11) "Foo::null()"
NULL
string(11) "Foo::self()"
string(11) "Foo::null()"
NULL
string(11) "Foo::self()"
string(11) "Foo::null()"
NULL
string(11) "Foo::self()"
string(11) "Foo::null()"
NULL
string(11) "Foo::self()"
string(38) "Cannot use object of type Foo as array"
41 changes: 41 additions & 0 deletions Zend/tests/nullsafe_method_call/002.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
--TEST--
Test nullsafe strict type check
--FILE--
<?php

try {
false?->bar();
} catch (Throwable $e) {
var_dump($e->getMessage());
}

try {
[]?->bar();
} catch (Throwable $e) {
var_dump($e->getMessage());
}

try {
(0)?->bar();
} catch (Throwable $e) {
var_dump($e->getMessage());
}

try {
(0.0)?->bar();
} catch (Throwable $e) {
var_dump($e->getMessage());
}

try {
''?->bar();
} catch (Throwable $e) {
var_dump($e->getMessage());
}

--EXPECT--
string(39) "Call to a member function bar() on bool"
string(40) "Call to a member function bar() on array"
string(38) "Call to a member function bar() on int"
string(40) "Call to a member function bar() on float"
string(41) "Call to a member function bar() on string"
30 changes: 30 additions & 0 deletions Zend/tests/nullsafe_method_call/003.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
--TEST--
Test basic nullsafe property fetching
--FILE--
<?php

class Foo {
public $bar = 'bar';
}

$null = null;
$foo = new Foo();

var_dump(null?->foo);
var_dump((new Foo)?->bar);
var_dump((new Foo)?->baz);
var_dump("{$null?->foo}");
var_dump("{$foo?->bar}");
var_dump("{$foo?->baz}");

--EXPECTF--
NULL
string(3) "bar"

Warning: Undefined property: Foo::$baz in %s003.php on line 12
NULL
string(0) ""
string(3) "bar"

Warning: Undefined property: Foo::$baz in %s003.php on line 15
string(0) ""
22 changes: 22 additions & 0 deletions Zend/tests/nullsafe_method_call/004.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--TEST--
Test nullsafe property assignment error
--FILE--
<?php

class Foo {
public $bar;
}

function test(?Foo $foo) {
var_dump($foo?->bar = 'bar');
var_dump($foo?->bar);
}

test(null);
test(new Foo());

--EXPECT--
NULL
NULL
string(3) "bar"
string(3) "bar"
22 changes: 22 additions & 0 deletions Zend/tests/nullsafe_method_call/005.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--TEST--
Test nullsafe property assignment op error
--FILE--
<?php

class Foo {
public $bar = 0;
}

function test(?Foo $foo) {
var_dump($foo?->bar = 1);
var_dump($foo?->bar);
}

test(null);
test(new Foo());

--EXPECT--
NULL
NULL
int(1)
int(1)
28 changes: 28 additions & 0 deletions Zend/tests/nullsafe_method_call/006.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
--TEST--
Test nullsafe property post increment/decrement error
--FILE--
<?php

class Foo {
public $bar = 0;
}

function test(?Foo $foo) {
var_dump(++$foo?->bar);
var_dump($foo?->bar);
var_dump(--$foo?->bar);
var_dump($foo?->bar);
}

test(null);
test(new Foo());

--EXPECT--
NULL
NULL
NULL
NULL
int(1)
int(1)
int(0)
int(0)
28 changes: 28 additions & 0 deletions Zend/tests/nullsafe_method_call/007.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
--TEST--
Test nullsafe property pre increment/decrement error
--FILE--
<?php

class Foo {
public $bar = 0;
}

function test(?Foo $foo) {
var_dump($foo?->bar++);
var_dump($foo?->bar);
var_dump($foo?->bar--);
var_dump($foo?->bar);
}

test(null);
test(new Foo());

--EXPECT--
NULL
NULL
NULL
NULL
int(0)
int(1)
int(1)
int(0)
24 changes: 24 additions & 0 deletions Zend/tests/nullsafe_method_call/008.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
--TEST--
Test nullsafe property coalesce assignment error
--SKIPIF--
<?php if(extension_loaded("Zend OPcache")) die("skip with opcache because SSA incorrectly optimized"); ?>
--FILE--
<?php

class Foo {
public $bar;
}

function test(?Foo $foo) {
var_dump($foo?->bar ??= 'bar');
var_dump($foo?->bar);
}

test(null);
test(new Foo());

--EXPECT--
NULL
NULL
string(3) "bar"
string(3) "bar"
23 changes: 23 additions & 0 deletions Zend/tests/nullsafe_method_call/009.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
--TEST--
Test fetch nullsafe property by ref error
--FILE--
<?php

class Foo {
public $bar;
}

function test(?Foo $foo) {
var_dump($ref = &$foo?->bar);
$ref = 'bar';
var_dump($foo?->bar);
}

test(null);
test(new Foo());

--EXPECT--
NULL
NULL
NULL
string(3) "bar"
30 changes: 30 additions & 0 deletions Zend/tests/nullsafe_method_call/010.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
--TEST--
Test fetch nested nullsafe property by ref error
--FILE--
<?php

class Foo {
public $bar;
}

class Bar {
public $baz;
}

function test(?Foo $foo) {
var_dump($ref = &$foo?->bar->baz);
$ref = 'baz';
var_dump($foo?->bar->baz);
}

test(null);

$foo = new Foo();
$foo->bar = new Bar();
test($foo);

--EXPECT--
NULL
NULL
NULL
string(3) "baz"
34 changes: 34 additions & 0 deletions Zend/tests/nullsafe_method_call/011.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
--TEST--
Test isset and empty on nullsafe property
--FILE--
<?php

class Foo {
public $bar;
}

// FIXME: These should not emit an "Undefined variable" warning
var_dump(isset($foo?->bar));
var_dump(empty($foo?->bar));

$foo = null;
var_dump(isset($foo?->bar));
var_dump(empty($foo?->bar));

$foo = new Foo();
var_dump(isset($foo?->bar));
var_dump(empty($foo?->bar));

$foo->bar = 'bar';
var_dump(isset($foo?->bar));
var_dump(empty($foo?->bar));

--EXPECT--
bool(false)
bool(true)
bool(false)
bool(true)
bool(false)
bool(true)
bool(true)
bool(false)

0 comments on commit f5785fd

Please sign in to comment.