Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 4 additions & 4 deletions Zend/tests/bug26698.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ Bug #26698 (Thrown exceptions while evaluting argument to pass as parameter cras

ini_set("report_memleaks", 0); // the exception thrown in this test results in a memory leak, which is fine

class Object
class ObjectOne
{
function getNone()
{
Expand All @@ -23,7 +23,7 @@ class Proxy
{
try
{
$res = new Object();
$res = new ObjectOne();
$this->three($res->getNone());
}
catch(Exception $e)
Expand All @@ -36,7 +36,7 @@ class Proxy
{
try
{
$res = new Object();
$res = new ObjectOne();
$this->three(1, $res->getNone());
}
catch(Exception $e)
Expand All @@ -49,7 +49,7 @@ class Proxy
{
try
{
$res = new Object();
$res = new ObjectOne();
$this->three(1, 2, $res->getNone());
}
catch(Exception $e)
Expand Down
12 changes: 6 additions & 6 deletions Zend/tests/bug28444.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ function my_error_handler($errno, $errstr, $errfile, $errline) {

set_error_handler('my_error_handler');

class Object
class ObjectOne
{
public $x;

Expand All @@ -26,7 +26,7 @@ class Overloaded

function __construct($x)
{
$this->x = new Object($x);
$this->x = new ObjectOne($x);
}

function __get($prop)
Expand All @@ -47,7 +47,7 @@ var_dump($y->x->x);
var_dump($y->x->x = 3);
var_dump($y->y = 3);
var_dump($y->y);
var_dump($y->z = new Object(4));
var_dump($y->z = new ObjectOne(4));
var_dump($y->z->x);
$t = $y->z;
var_dump($t->x = 5);
Expand All @@ -56,7 +56,7 @@ var_dump($y->z->x = 6);
?>
===DONE===
--EXPECTF--
object(Object)#%d (1) {
object(ObjectOne)#%d (1) {
["x"]=>
int(2)
}
Expand All @@ -66,9 +66,9 @@ Overloaded::__set(y,3)
int(3)
Overloaded::__get(y)
int(3)
string(55) "Object of class Object could not be converted to string"
string(58) "Object of class ObjectOne could not be converted to string"
Overloaded::__set(z,)
object(Object)#%d (1) {
object(ObjectOne)#%d (1) {
["x"]=>
int(4)
}
Expand Down
4 changes: 2 additions & 2 deletions Zend/tests/bug60598.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ define('OBJECT_COUNT', 10000);

$containers = array();

class Object {
class ObjectOne {
protected $_guid = 0;
public function __construct() {
global $containers;
Expand All @@ -20,7 +20,7 @@ class Object {
}

for ($i = 0; $i < OBJECT_COUNT; ++$i) {
new Object();
new ObjectOne();
}

// You probably won't see this because of the "zend_mm_heap corrupted"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
--TEST--
Missing class method a object return type during inheritance
--FILE--
<?php

class One {
public function a() : object {}
}

class Two extends One {
public function a() {}
}

--EXPECTF--
Fatal error: Declaration of Two::a() must be compatible with One::a(): object in %s on line 9
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
--TEST--
Missing interface method a object return type during inheritance
--FILE--
<?php

interface One {
public function a() : object {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The test description doesn't match the actual body

}

interface Two extends One {
public function a() {}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be awesome to have covariance support for return type hints stricter than object.

This way, you could have:

interface Repo { public function find(Uuid $id) : object; }
class UserRepo { public function find(Uuid $id) : User; }

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should be fine to add this. We're okay with return type covariance where it does not cause technical issues. E.g. iterable to Traversable also works.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But why there is no support for the same thing in arguments?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in arguments, that breaks variance: a consumer relying on the interface will bot work when an implementation has stricter parameter types.

To solve that, there was a recent discussion at https://wiki.php.net/rfc/never_for_parameter_types

}

--EXPECTF--
Fatal error: Interface function One::a() cannot contain body in %s on line 4
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is probably not what you want to test here ;)

26 changes: 26 additions & 0 deletions Zend/tests/object_types/return_type_in_class.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
--TEST--
Adding a class method object return type
--FILE--
<?php

interface One {
public function a() : object;
}

class Two implements One {
public function a() : object {}
}

$three = new class extends Two {
public function a() : object {
return 12345;
}
};
$three->a();
--EXPECTF--

Fatal error: Uncaught TypeError: Return value of class@anonymous::a() must be an object, integer returned in %s:13
Stack trace:
#0 %s(16): class@anonymous->a()
#1 {main}
thrown in %s on line 13
16 changes: 16 additions & 0 deletions Zend/tests/object_types/return_type_in_function.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
--TEST--
Adding a function object return type
--FILE--
<?php

function a() : object {
return 12345;
}
a();
--EXPECTF--

Fatal error: Uncaught TypeError: Return value of a() must be an object, integer returned in %s:4
Stack trace:
#0 %s(6): a()
#1 {main}
thrown in %s on line 4
22 changes: 22 additions & 0 deletions Zend/tests/object_types/return_type_in_interface.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--TEST--
Adding a interface method object return type
--FILE--
<?php

interface One {
public function a() : object;
}

$two = new class implements One {
public function a() : object {
return 12345;
}
};
$two->a();
--EXPECTF--

Fatal error: Uncaught TypeError: Return value of class@anonymous::a() must be an object, integer returned in %s:9
Stack trace:
#0 %s(12): class@anonymous->a()
#1 {main}
thrown in %s on line 9
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test looks redundant with Zend/tests/object_types/return_type_in_class.phpt, which also has an object type on the interface.

26 changes: 26 additions & 0 deletions Zend/tests/object_types/return_type_inheritance_in_class.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
--TEST--
Adding class method a object return type during inheritance is allowed
--FILE--
<?php

class One {
public function a() {}
}

class Two extends One {
public function a() : object {}
}

$three = new class extends Two {
public function a() : object {
return 12345;
}
};
$three->a();

--EXPECTF--
Fatal error: Uncaught TypeError: Return value of class@anonymous::a() must be an object, integer returned in %s:13
Stack trace:
#0 %s(16): class@anonymous->a()
#1 {main}
thrown in /%s on line 13
26 changes: 26 additions & 0 deletions Zend/tests/object_types/return_type_inheritance_in_interface.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
--TEST--
Adding interface method a object return type during inheritance is allowed
--FILE--
<?php

interface One {
public function a();
}

interface Two extends One {
public function a() : object;
}

$three = new class implements Two {
public function a() : object {
return 12345;
}
};
$three->a();

--EXPECTF--
Fatal error: Uncaught TypeError: Return value of class@anonymous::a() must be an object, integer returned in %s:13
Stack trace:
#0 %s(16): class@anonymous->a()
#1 {main}
thrown in /%s on line 13
31 changes: 31 additions & 0 deletions Zend/tests/object_types/return_type_reflection.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
--TEST--
Reflecting object return type
--FILE--
<?php

interface One {
public function a() : object;
}

class Two implements One {
public function a() : object {}
}

function a() : object {}

$returnTypeOne = (new ReflectionClass(One::class))->getMethod('a')->getReturnType();
var_dump($returnTypeOne->isBuiltin(), (string)$returnTypeOne);

$returnTypeTwo = (new ReflectionClass(Two::class))->getMethod('a')->getReturnType();
var_dump($returnTypeTwo->isBuiltin(), (string)$returnTypeTwo);

$returnTypea = (new ReflectionFunction('a'))->getReturnType();
var_dump($returnTypea->isBuiltin(), (string)$returnTypea);

--EXPECTF--
bool(true)
string(6) "object"
bool(true)
string(6) "object"
bool(true)
string(6) "object"
19 changes: 19 additions & 0 deletions Zend/tests/object_types/type_hint_in_class_method.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
--TEST--
Adding a class method object type hint
--FILE--
<?php

class One {
public function a(object $obj) {}
}

$one = new One();
$one->a(new One());
$one->a(123);
--EXPECTF--

Fatal error: Uncaught TypeError: Argument 1 passed to One::a() must be an object, integer given, called in %s:4
Stack trace:
#0 %s(9): One->a(123)
#1 {main}
thrown in %s on line 4
17 changes: 17 additions & 0 deletions Zend/tests/object_types/type_hint_in_function.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
--TEST--
Adding a function object type hint
--FILE--
<?php

class A {}
function a(object $obj) {}

a(new A());
a(123);
--EXPECTF--

Fatal error: Uncaught TypeError: Argument 1 passed to a() must be an object, integer given, called in %s.php on line 7 and defined in %s:4
Stack trace:
#0 %s(7): a(123)
#1 {main}
thrown in %s on line 4
31 changes: 31 additions & 0 deletions Zend/tests/object_types/type_hint_reflection.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
--TEST--
Reflecting object type hint
--FILE--
<?php

interface One {
public function a(object $obj);
}

class Two implements One {
public function a(object $obj) {}
}

function a(object $obj) {}

$typeHintOne = (new ReflectionClass(One::class))->getMethod('a')->getParameters()[0]->getType();
var_dump($typeHintOne->isBuiltin(), (string)$typeHintOne);

$typeHintTwo = (new ReflectionClass(Two::class))->getMethod('a')->getParameters()[0]->getType();
var_dump($typeHintTwo->isBuiltin(), (string)$typeHintTwo);

$typeHinta = (new ReflectionFunction('a'))->getParameters()[0]->getType();
var_dump($typeHinta->isBuiltin(), (string)$typeHinta);

--EXPECTF--
bool(true)
string(6) "object"
bool(true)
string(6) "object"
bool(true)
string(6) "object"
2 changes: 2 additions & 0 deletions Zend/zend_compile.c
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ static const struct reserved_class_name reserved_class_names[] = {
{ZEND_STRL("true")},
{ZEND_STRL("void")},
{ZEND_STRL("iterable")},
{ZEND_STRL("object")},
{NULL, 0}
};

Expand Down Expand Up @@ -206,6 +207,7 @@ static const builtin_type_info builtin_types[] = {
{ZEND_STRL("bool"), _IS_BOOL},
{ZEND_STRL("void"), IS_VOID},
{ZEND_STRL("iterable"), IS_ITERABLE},
{ZEND_STRL("object"), IS_OBJECT},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wait... This is all there is to the patch? 😵

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, that's all what is needed :)

{NULL, 0, IS_UNDEF}
};

Expand Down
5 changes: 4 additions & 1 deletion Zend/zend_execute.c
Original file line number Diff line number Diff line change
Expand Up @@ -616,7 +616,6 @@ static ZEND_COLD void zend_verify_type_error_common(
{
zend_bool is_interface = 0;
*fname = ZSTR_VAL(zf->common.function_name);

if (zf->common.scope) {
*fsep = "::";
*fclass = ZSTR_VAL(zf->common.scope->name);
Expand All @@ -642,6 +641,10 @@ static ZEND_COLD void zend_verify_type_error_common(
}
} else {
switch (ZEND_TYPE_CODE(arg_info->type)) {
case IS_OBJECT:
*need_msg = "be an ";
*need_kind = "object";
break;
case IS_CALLABLE:
*need_msg = "be callable";
*need_kind = "";
Expand Down
Loading