. Fixed bug #74761 (Unary operator expected error on some systems). (petk)
. Allow loading PHP/Zend extensions by name in ini files (extension=<name>).
(francois at tekwire dot net)
+ . Added object type annotation. (brzuchal)
- OpenSSL:
. Fixed bug #74798 (pkcs7_en/decrypt does not work if \x0a is used in content).
. Minimum supported Windows versions are Windows 7/Server 2008 R2.
. Initial trait property value compatibility check will no longer perform
any casts. (Bug #74269)
+ . "object" (in any case) can no longer be used as a class name.
- BCMath:
. The bcmod() function no longer truncates fractional numbers to integers. As
(https://wiki.php.net/rfc/allow-abstract-function-override)
. A trailing comma in group use statements is now allowed.
(https://wiki.php.net/rfc/list-syntax-trailing-commas)
+ . The "object" type annotation is now supported.
+ (https://wiki.php.net/rfc/object-typehint)
- DBA:
. Implemented support for the LMDB backend.
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()
{
{
try
{
- $res = new Object();
+ $res = new ObjectOne();
$this->three($res->getNone());
}
catch(Exception $e)
{
try
{
- $res = new Object();
+ $res = new ObjectOne();
$this->three(1, $res->getNone());
}
catch(Exception $e)
{
try
{
- $res = new Object();
+ $res = new ObjectOne();
$this->three(1, 2, $res->getNone());
}
catch(Exception $e)
set_error_handler('my_error_handler');
-class Object
+class ObjectOne
{
public $x;
function __construct($x)
{
- $this->x = new Object($x);
+ $this->x = new ObjectOne($x);
}
function __get($prop)
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);
?>
===DONE===
--EXPECTF--
-object(Object)#%d (1) {
+object(ObjectOne)#%d (1) {
["x"]=>
int(2)
}
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)
}
$containers = array();
-class Object {
+class ObjectOne {
protected $_guid = 0;
public function __construct() {
global $containers;
}
for ($i = 0; $i < OBJECT_COUNT; ++$i) {
- new Object();
+ new ObjectOne();
}
// You probably won't see this because of the "zend_mm_heap corrupted"
--- /dev/null
+--TEST--
+Object type can only default to null
+--FILE--
+<?php
+
+function test(object $obj = 42) { }
+
+?>
+--EXPECTF--
+Fatal error: Default value for parameters with a object type can only be NULL in %s on line %d
--- /dev/null
+--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
\ No newline at end of file
--- /dev/null
+--TEST--
+Missing interface method a object return type during inheritance
+--FILE--
+<?php
+
+interface One {
+ public function a() : object;
+}
+
+interface Two extends One {
+ public function a();
+}
+
+--EXPECTF--
+Fatal error: Declaration of Two::a() must be compatible with One::a(): object in %s on line %d
--- /dev/null
+--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
--- /dev/null
+--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
\ No newline at end of file
--- /dev/null
+--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
--- /dev/null
+--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
--- /dev/null
+--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"
\ No newline at end of file
--- /dev/null
+--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
\ No newline at end of file
--- /dev/null
+--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
\ No newline at end of file
--- /dev/null
+--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"
\ No newline at end of file
{ZEND_STRL("true")},
{ZEND_STRL("void")},
{ZEND_STRL("iterable")},
+ {ZEND_STRL("object")},
{NULL, 0}
};
{ZEND_STRL("bool"), _IS_BOOL},
{ZEND_STRL("void"), IS_VOID},
{ZEND_STRL("iterable"), IS_ITERABLE},
+ {ZEND_STRL("object"), IS_OBJECT},
{NULL, 0, IS_UNDEF}
};
"with iterable type can only be an array or NULL");
}
break;
+
+ case IS_OBJECT:
+ zend_error_noreturn(E_COMPILE_ERROR, "Default value for parameters "
+ "with a %s type can only be NULL",
+ zend_get_type_by_const(ZEND_TYPE_CODE(arg_info->type)), zend_get_type_by_const(ZEND_TYPE_CODE(arg_info->type)));
+ break;
default:
if (!ZEND_SAME_FAKE_TYPE(ZEND_TYPE_CODE(arg_info->type), Z_TYPE(default_node.u.constant))) {
{
zend_bool is_interface = 0;
*fname = ZSTR_VAL(zf->common.function_name);
-
if (zf->common.scope) {
*fsep = "::";
*fclass = ZSTR_VAL(zf->common.scope->name);
}
} 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 = "";
Reflection Bug #38194 (ReflectionClass::isSubclassOf() returns TRUE for the class itself)
--FILE--
<?php
-class Object { }
+class ObjectOne { }
-$objectClass= new ReflectionClass('Object');
+$objectClass = new ReflectionClass('ObjectOne');
var_dump($objectClass->isSubclassOf($objectClass));
?>
--EXPECT--
--FILE--
<?php
-class Object {
+class ObjectOne {
public function __construct() {
}
}
-$class= new ReflectionClass('Object');
+$class= new ReflectionClass('ObjectOne');
var_dump($class->newInstanceArgs());
-class Object1 {
+class ObjectTwo {
public function __construct($var) {
var_dump($var);
}
}
-$class= new ReflectionClass('Object1');
+$class= new ReflectionClass('ObjectTwo');
try {
var_dump($class->newInstanceArgs());
} catch (Throwable $e) {
echo "Done\n";
?>
--EXPECTF--
-object(Object)#%d (0) {
+object(ObjectOne)#%d (0) {
}
-Exception: Too few arguments to function Object1::__construct(), 0 passed and exactly 1 expected
+Exception: Too few arguments to function ObjectTwo::__construct(), 0 passed and exactly 1 expected
string(4) "test"
-object(Object1)#%d (0) {
+object(ObjectTwo)#%d (0) {
}
Done
ZE2 ArrayAccess
--FILE--
<?php
-class object implements ArrayAccess {
+class ObjectOne implements ArrayAccess {
public $a = array('1st', 1, 2=>'3rd', '4th'=>4);
}
}
-$obj = new Object;
+$obj = new ObjectOne;
var_dump($obj->a);
int(4)
}
===EMPTY===
-object::offsetExists(0)
-object::offsetGet(0)
+ObjectOne::offsetExists(0)
+ObjectOne::offsetGet(0)
bool(false)
-object::offsetExists(1)
-object::offsetGet(1)
+ObjectOne::offsetExists(1)
+ObjectOne::offsetGet(1)
bool(false)
-object::offsetExists(2)
-object::offsetGet(2)
+ObjectOne::offsetExists(2)
+ObjectOne::offsetGet(2)
bool(false)
-object::offsetExists(4th)
-object::offsetGet(4th)
+ObjectOne::offsetExists(4th)
+ObjectOne::offsetGet(4th)
bool(false)
-object::offsetExists(5th)
+ObjectOne::offsetExists(5th)
bool(true)
-object::offsetExists(6)
+ObjectOne::offsetExists(6)
bool(true)
===isset===
-object::offsetExists(0)
+ObjectOne::offsetExists(0)
bool(true)
-object::offsetExists(1)
+ObjectOne::offsetExists(1)
bool(true)
-object::offsetExists(2)
+ObjectOne::offsetExists(2)
bool(true)
-object::offsetExists(4th)
+ObjectOne::offsetExists(4th)
bool(true)
-object::offsetExists(5th)
+ObjectOne::offsetExists(5th)
bool(false)
-object::offsetExists(6)
+ObjectOne::offsetExists(6)
bool(false)
===offsetGet===
-object::offsetGet(0)
+ObjectOne::offsetGet(0)
string(3) "1st"
-object::offsetGet(1)
+ObjectOne::offsetGet(1)
int(1)
-object::offsetGet(2)
+ObjectOne::offsetGet(2)
string(3) "3rd"
-object::offsetGet(4th)
+ObjectOne::offsetGet(4th)
int(4)
-object::offsetGet(5th)
+ObjectOne::offsetGet(5th)
Notice: Undefined index: 5th in %sarray_access_001.php on line %d
NULL
-object::offsetGet(6)
+ObjectOne::offsetGet(6)
Notice: Undefined offset: 6 in %sarray_access_001.php on line %d
NULL
===offsetSet===
WRITE 1
-object::offsetSet(1,Changed 1)
-object::offsetGet(1)
+ObjectOne::offsetSet(1,Changed 1)
+ObjectOne::offsetGet(1)
string(9) "Changed 1"
WRITE 2
-object::offsetSet(4th,Changed 4th)
-object::offsetGet(4th)
+ObjectOne::offsetSet(4th,Changed 4th)
+ObjectOne::offsetGet(4th)
string(11) "Changed 4th"
WRITE 3
-object::offsetSet(5th,Added 5th)
-object::offsetGet(5th)
+ObjectOne::offsetSet(5th,Added 5th)
+ObjectOne::offsetGet(5th)
string(9) "Added 5th"
WRITE 4
-object::offsetSet(6,Added 6)
-object::offsetGet(6)
+ObjectOne::offsetSet(6,Added 6)
+ObjectOne::offsetGet(6)
string(7) "Added 6"
-object::offsetGet(0)
+ObjectOne::offsetGet(0)
string(3) "1st"
-object::offsetGet(2)
+ObjectOne::offsetGet(2)
string(3) "3rd"
-object::offsetSet(6,changed 6)
-object::offsetGet(6)
+ObjectOne::offsetSet(6,changed 6)
+ObjectOne::offsetGet(6)
string(9) "changed 6"
string(9) "changed 6"
===unset===
[6]=>
string(9) "changed 6"
}
-object::offsetUnset(2)
-object::offsetUnset(4th)
-object::offsetUnset(7)
-object::offsetUnset(8th)
+ObjectOne::offsetUnset(2)
+ObjectOne::offsetUnset(4th)
+ObjectOne::offsetUnset(7)
+ObjectOne::offsetUnset(8th)
array(4) {
[0]=>
string(3) "1st"
ZE2 ArrayAccess::offsetSet without return
--FILE--
<?php
-class object implements ArrayAccess {
+class ObjectOne implements ArrayAccess {
public $a = array('1st', 1, 2=>'3rd', '4th'=>4);
}
}
-$obj = new Object;
+$obj = new ObjectOne;
var_dump($obj->a);
int(4)
}
===EMPTY===
-object::offsetExists(0)
-object::offsetGet(0)
+ObjectOne::offsetExists(0)
+ObjectOne::offsetGet(0)
bool(false)
-object::offsetExists(1)
-object::offsetGet(1)
+ObjectOne::offsetExists(1)
+ObjectOne::offsetGet(1)
bool(false)
-object::offsetExists(2)
-object::offsetGet(2)
+ObjectOne::offsetExists(2)
+ObjectOne::offsetGet(2)
bool(false)
-object::offsetExists(4th)
-object::offsetGet(4th)
+ObjectOne::offsetExists(4th)
+ObjectOne::offsetGet(4th)
bool(false)
-object::offsetExists(5th)
+ObjectOne::offsetExists(5th)
bool(true)
-object::offsetExists(6)
+ObjectOne::offsetExists(6)
bool(true)
===isset===
-object::offsetExists(0)
+ObjectOne::offsetExists(0)
bool(true)
-object::offsetExists(1)
+ObjectOne::offsetExists(1)
bool(true)
-object::offsetExists(2)
+ObjectOne::offsetExists(2)
bool(true)
-object::offsetExists(4th)
+ObjectOne::offsetExists(4th)
bool(true)
-object::offsetExists(5th)
+ObjectOne::offsetExists(5th)
bool(false)
-object::offsetExists(6)
+ObjectOne::offsetExists(6)
bool(false)
===offsetGet===
-object::offsetGet(0)
+ObjectOne::offsetGet(0)
string(3) "1st"
-object::offsetGet(1)
+ObjectOne::offsetGet(1)
int(1)
-object::offsetGet(2)
+ObjectOne::offsetGet(2)
string(3) "3rd"
-object::offsetGet(4th)
+ObjectOne::offsetGet(4th)
int(4)
-object::offsetGet(5th)
+ObjectOne::offsetGet(5th)
Notice: Undefined index: 5th in %sarray_access_002.php on line %d
NULL
-object::offsetGet(6)
+ObjectOne::offsetGet(6)
Notice: Undefined offset: 6 in %sarray_access_002.php on line %d
NULL
===offsetSet===
WRITE 1
-object::offsetSet(1,Changed 1)
-object::offsetGet(1)
+ObjectOne::offsetSet(1,Changed 1)
+ObjectOne::offsetGet(1)
string(9) "Changed 1"
WRITE 2
-object::offsetSet(4th,Changed 4th)
-object::offsetGet(4th)
+ObjectOne::offsetSet(4th,Changed 4th)
+ObjectOne::offsetGet(4th)
string(11) "Changed 4th"
WRITE 3
-object::offsetSet(5th,Added 5th)
-object::offsetGet(5th)
+ObjectOne::offsetSet(5th,Added 5th)
+ObjectOne::offsetGet(5th)
string(9) "Added 5th"
WRITE 4
-object::offsetSet(6,Added 6)
-object::offsetGet(6)
+ObjectOne::offsetSet(6,Added 6)
+ObjectOne::offsetGet(6)
string(7) "Added 6"
-object::offsetGet(0)
+ObjectOne::offsetGet(0)
string(3) "1st"
-object::offsetGet(2)
+ObjectOne::offsetGet(2)
string(3) "3rd"
-object::offsetSet(6,changed 6)
-object::offsetGet(6)
+ObjectOne::offsetSet(6,changed 6)
+ObjectOne::offsetGet(6)
string(9) "changed 6"
string(9) "changed 6"
===unset===
[6]=>
string(9) "changed 6"
}
-object::offsetUnset(2)
-object::offsetUnset(4th)
-object::offsetUnset(7)
-object::offsetUnset(8th)
+ObjectOne::offsetUnset(2)
+ObjectOne::offsetUnset(4th)
+ObjectOne::offsetUnset(7)
+ObjectOne::offsetUnset(8th)
array(4) {
[0]=>
string(3) "1st"
error_reporting=4095
--FILE--
<?php
-class object implements ArrayAccess {
+class ObjectOne implements ArrayAccess {
public $a = array('1st', 1, 2=>'3rd', '4th'=>4);
}
}
-$obj = new Object;
+$obj = new ObjectOne;
var_dump($obj[1]);
var_dump($obj[2]);
?>
===DONE===
--EXPECTF--
-object::offsetGet(1)
+ObjectOne::offsetGet(1)
string(6) "fooBar"
-object::offsetGet(2)
+ObjectOne::offsetGet(2)
int(1)
-object::offsetGet(2)
+ObjectOne::offsetGet(2)
-Notice: Indirect modification of overloaded element of object has no effect in %sarray_access_003.php on line 39
-object::offsetGet(2)
+Notice: Indirect modification of overloaded element of ObjectOne has no effect in %sarray_access_003.php on line 39
+ObjectOne::offsetGet(2)
int(1)
===DONE===
ZE2 ArrayAccess::offsetGet ambiguties
--FILE--
<?php
-class object implements ArrayAccess {
+class ObjectOne implements ArrayAccess {
public $a = array('1st', 1, 2=>'3rd', '4th'=>4);
}
}
-$obj = new Object;
+$obj = new ObjectOne;
var_dump($obj[1]);
var_dump($obj[2]);
?>
===DONE===
--EXPECTF--
-object::offsetGet(1)
+ObjectOne::offsetGet(1)
string(6) "fooBar"
-object::offsetGet(2)
+ObjectOne::offsetGet(2)
int(1)
-object::offsetGet(2)
+ObjectOne::offsetGet(2)
-Notice: Indirect modification of overloaded element of object has no effect in %sarray_access_004.php on line 39
-object::offsetGet(2)
+Notice: Indirect modification of overloaded element of ObjectOne has no effect in %sarray_access_004.php on line 39
+ObjectOne::offsetGet(2)
int(1)
===DONE===