Skip to content

Commit 18d7837

Browse files
authored
Deprecate returning values from __construct() and __destruct() (php#21982)
* Deprecate returning values from `__construct()` and `__destruct()` * Deprecate making `__construct()` and `__destruct()` a `Generator` * NEWS / UPGRADING
1 parent 0c1d809 commit 18d7837

10 files changed

Lines changed: 87 additions & 12 deletions

File tree

NEWS

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ PHP NEWS
3737
. Fixed bug GH-22257 (type confusion in Exception::getTraceAsString()).
3838
(David Carlier)
3939
. TSRM: make CG, EG, SCNG and AG compile-time offsets. (henderkes)
40+
. Deprecate returning values from __construct() and __destruct(). (timwolla)
4041

4142
- BCMath:
4243
. Added NUL-byte validation to BCMath functions. (jorgsowa)

UPGRADING

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,10 @@ PHP 8.6 UPGRADE NOTES
283283
- Core:
284284
. Specifying a return type of array|null / ?array for __debugInfo() is now
285285
deprecated. Specify array instead.
286+
. Returning values from __construct() and __destruct() is now deprecated.
287+
RFC: https://wiki.php.net/rfc/deprecate-return-value-from-construct
288+
. Making __construct() and __destruct() a Generator is now deprecated.
289+
RFC: https://wiki.php.net/rfc/deprecate-return-value-from-construct
286290

287291
- GMP
288292
. The shift (<<, >>) and exponentiation (**) operators on GMP objects now
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
--TEST--
2+
Returning values from constructors and destructors is deprecated
3+
--FILE--
4+
<?php
5+
6+
class A {
7+
public function __construct() { return ''; }
8+
public function __destruct() { return ''; }
9+
}
10+
11+
class B {
12+
public function __construct() { return $this->voidMethod(); }
13+
public function __destruct() { return $this->voidMethod(); }
14+
15+
public function voidMethod(): void { }
16+
}
17+
18+
class Gen {
19+
public function __construct() { yield ''; }
20+
public function __destruct() { yield ''; }
21+
}
22+
23+
?>
24+
--EXPECTF--
25+
Deprecated: Returning a value from a constructor is deprecated in %s on line %d
26+
27+
Deprecated: Returning a value from a destructor is deprecated in %s on line %d
28+
29+
Deprecated: Returning a value from a constructor is deprecated in %s on line %d
30+
31+
Deprecated: Returning a value from a destructor is deprecated in %s on line %d
32+
33+
Deprecated: Making a constructor a Generator is deprecated in %s on line %d
34+
35+
Deprecated: Making a destructor a Generator is deprecated in %s on line %d

Zend/tests/prop_const_expr/non_enums_catchable.phpt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const A_prop = (new A)->{new Printer ? 'printer' : null};
1818

1919
?>
2020
--EXPECTF--
21+
Deprecated: Returning a value from a constructor is deprecated in %s on line %d
2122
Printer
2223

2324
Fatal error: Uncaught Error: Fetching properties on non-enums in constant expressions is not allowed in %s:%d

Zend/tests/traits/bug60536_001.phpt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,9 @@ $a->__construct();
2323
echo "DONE";
2424
?>
2525
--EXPECTF--
26+
Deprecated: Returning a value from a constructor is deprecated in %s on line %d
27+
28+
Deprecated: Returning a value from a constructor is deprecated in %s on line %d
29+
2630
Warning: Undefined property: Z::$x in %s on line %d
2731
DONE

Zend/zend_compile.c

Lines changed: 24 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -530,6 +530,12 @@ ZEND_API bool zend_is_compiling(void) /* {{{ */
530530
}
531531
/* }}} */
532532

533+
static bool zend_is_constructor(const zend_string *name) /* {{{ */
534+
{
535+
return zend_string_equals_literal_ci(name, ZEND_CONSTRUCTOR_FUNC_NAME);
536+
}
537+
/* }}} */
538+
533539
static zend_always_inline uint32_t get_temporary_variable(void) /* {{{ */
534540
{
535541
return (uint32_t)CG(active_op_array)->T++;
@@ -5549,12 +5555,6 @@ static void zend_compile_method_call(znode *result, zend_ast *ast, uint32_t type
55495555
}
55505556
/* }}} */
55515557

5552-
static bool zend_is_constructor(const zend_string *name) /* {{{ */
5553-
{
5554-
return zend_string_equals_literal_ci(name, ZEND_CONSTRUCTOR_FUNC_NAME);
5555-
}
5556-
/* }}} */
5557-
55585558
static bool is_func_accessible(const zend_function *fbc)
55595559
{
55605560
if ((fbc->common.fn_flags & ZEND_ACC_PUBLIC) || fbc->common.scope == CG(active_class_entry)) {
@@ -5993,6 +5993,16 @@ static void zend_compile_return(const zend_ast *ast) /* {{{ */
59935993
zend_compile_expr(&expr_node, expr_ast);
59945994
}
59955995

5996+
if (expr_ast) {
5997+
if (CG(active_class_entry) != NULL) {
5998+
if (zend_is_constructor(CG(active_op_array)->function_name)) {
5999+
zend_error(E_DEPRECATED, "Returning a value from a constructor is deprecated");
6000+
} else if (zend_string_equals_literal_ci(CG(active_op_array)->function_name, ZEND_DESTRUCTOR_FUNC_NAME)) {
6001+
zend_error(E_DEPRECATED, "Returning a value from a destructor is deprecated");
6002+
}
6003+
}
6004+
}
6005+
59966006
if ((CG(active_op_array)->fn_flags & ZEND_ACC_HAS_FINALLY_BLOCK)
59976007
&& (expr_node.op_type == IS_CV || (by_ref && expr_node.op_type == IS_VAR))
59986008
&& zend_has_finally()) {
@@ -8843,6 +8853,14 @@ static zend_op_array *zend_compile_func_decl_ex(
88438853
zend_compile_params(params_ast, return_type_ast,
88448854
is_method && zend_string_equals_literal(lcname, ZEND_TOSTRING_FUNC_LCNAME) ? IS_STRING : 0);
88458855
if (CG(active_op_array)->fn_flags & ZEND_ACC_GENERATOR) {
8856+
if (CG(active_class_entry) != NULL) {
8857+
if (zend_is_constructor(CG(active_op_array)->function_name)) {
8858+
zend_error(E_DEPRECATED, "Making a constructor a Generator is deprecated");
8859+
} else if (zend_string_equals_literal_ci(CG(active_op_array)->function_name, ZEND_DESTRUCTOR_FUNC_NAME)) {
8860+
zend_error(E_DEPRECATED, "Making a destructor a Generator is deprecated");
8861+
}
8862+
}
8863+
88468864
zend_mark_function_as_generator();
88478865
zend_emit_op(NULL, ZEND_GENERATOR_CREATE, NULL, NULL);
88488866
}

ext/pdo_mysql/tests/pdo_mysql_subclass.phpt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ $db = MySQLPDOTest::factory();
7676
$db->exec('DROP TABLE IF EXISTS test_subclass');
7777
?>
7878
--EXPECTF--
79+
Deprecated: Returning a value from a constructor is deprecated in %s on line %d
7980
__construct('%S', '%S', %s)
8081

8182
Deprecated: Callables of the form ["MyPDO", "parent::__construct"] are deprecated in %s on line %d

ext/reflection/tests/bug36434.phpt

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,9 @@ foreach ($r->GetProperties() as $p)
2626
}
2727

2828
?>
29-
--EXPECT--
29+
--EXPECTF--
30+
Deprecated: Returning a value from a constructor is deprecated in %s on line %d
31+
32+
Deprecated: Returning a value from a constructor is deprecated in %s on line %d
3033
bar foo
3134
ancestor ancestor

ext/standard/tests/array/gh16649/array_splice_uaf_original_case.phpt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,5 +25,6 @@ try {
2525
echo "Exception caught: " . $e->getMessage() . "\n";
2626
}
2727
?>
28-
--EXPECT--
28+
--EXPECTF--
29+
Deprecated: Returning a value from a destructor is deprecated in %s on line %d
2930
Exception caught: Array was modified during array_splice operation

ext/zend_test/tests/zend_object_init_with_constructor.phpt

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,14 @@ $o = zend_object_init_with_constructor("TestUserWithConstructorNoParams");
139139
var_dump($o);
140140
unset($o);
141141
?>
142-
--EXPECT--
142+
--EXPECTF--
143+
Deprecated: Returning a value from a constructor is deprecated in %s on line %d
144+
145+
Deprecated: Returning a value from a constructor is deprecated in %s on line %d
146+
147+
Deprecated: Returning a value from a constructor is deprecated in %s on line %d
148+
149+
Deprecated: Returning a value from a constructor is deprecated in %s on line %d
143150
Testing impossible initializations
144151
Error: Cannot instantiate interface _ZendTestInterface
145152
Error: Cannot instantiate trait _ZendTestTrait
@@ -152,14 +159,14 @@ Testing param passing
152159
ArgumentCountError: Too few arguments to function TestUserWithConstructorArgs::__construct(), 0 passed and exactly 2 expected
153160
TypeError: TestUserWithConstructorArgs::__construct(): Argument #1 ($int_param) must be of type int, string given
154161
Error: Unknown named parameter $unused_param
155-
object(TestUserWithConstructorArgs)#1 (0) {
162+
object(TestUserWithConstructorArgs)#%d (0) {
156163
}
157164
Destructor for TestUserWithConstructorArgs
158165
Passing too many args to constructor
159-
object(TestUserWithConstructorArgs)#1 (0) {
166+
object(TestUserWithConstructorArgs)#%d (0) {
160167
}
161168
Destructor for TestUserWithConstructorArgs
162169
Testing class with defined constructor and no params
163-
object(TestUserWithConstructorNoParams)#1 (0) {
170+
object(TestUserWithConstructorNoParams)#%d (0) {
164171
}
165172
Destructor for TestUserWithConstructorNoParams

0 commit comments

Comments
 (0)