Skip to content

Commit af15923

Browse files
IMSoPcmb69
authored andcommitted
Extend deprecation notices to is_callable($foo) and callable $foo
Implements https://wiki.php.net/rfc/partially-supported-callables-expand-deprecation-notices so that uses of "self" and "parent" in is_callable() and callable type constraints now raise a deprecation notice, independent of the one raised when and if the callable is actually invoked. A new flag is added to the existing check_flags parameter of zend_is_callable / zend_is_callable_ex, for use in internal calls that would otherwise repeat the notice multiple times. In particular, arguments to internal function calls are checked first based on arginfo, and then again during ZPP, so the former suppresses the deprecation notice. Some existing tests which raised this deprecation have been updated to avoid the syntax, but the existing version retained for maximum regression coverage until it is made an error. With thanks to Juliette Reinders Folmer for the RFC and initial investigation. Closes GH-8823.
1 parent 37e214b commit af15923

22 files changed

+409
-49
lines changed

UPGRADING

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -134,11 +134,10 @@ PHP 8.2 UPGRADE NOTES
134134
[new Foo, "Bar::method"]
135135

136136
This does not affect normal method callables like "A::method" or
137-
["A", "method"]. A deprecation notice is only emitted on call. Both
138-
is_callable() and the callable type will silently accept these callables
139-
until support for them is removed entirely.
137+
["A", "method"].
140138

141139
RFC: https://wiki.php.net/rfc/deprecate_partially_supported_callables
140+
RFC: https://wiki.php.net/rfc/partially-supported-callables-expand-deprecation-notices
142141

143142
. The "${var}" and "${expr}" style string interpolations are deprecated and
144143
will be removed in PHP 9. Use "$var"/"{$var}" or "{${expr}}", respectively.

UPGRADING.INTERNALS

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,11 @@ PHP 8.2 INTERNALS UPGRADE NOTES
4646
smart_str_trim_to_size() before returning the string.
4747
* It is recommended to use smart_str_extract() or smart_str_trim_to_size() when
4848
using the smart_str API.
49+
* zend_is_callable_ex, and functions which call it such as zend_is_callable and
50+
zend_fcall_info_init, will issue deprecation notices if passed values which
51+
are deprecated (see main UPGRADING notes). To suppress the notice, e.g. to
52+
avoid duplicates when processing the same value multiple times, pass or add
53+
IS_CALLABLE_SUPPRESS_DEPRECATIONS to the check_flags parameter.
4954

5055
========================
5156
2. Build system changes

Zend/tests/bug48899-deprecated.phpt

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
--TEST--
2+
Bug #48899 (is_callable returns true even if method does not exist in parent class) [original test with deprecated syntax]
3+
--FILE--
4+
<?php
5+
6+
class ParentClass { }
7+
8+
class ChildClass extends ParentClass {
9+
public function testIsCallable() {
10+
var_dump(is_callable(array($this, 'parent::testIsCallable')));
11+
}
12+
public function testIsCallable2() {
13+
var_dump(is_callable(array($this, 'static::testIsCallable2')));
14+
}
15+
}
16+
17+
$child = new ChildClass();
18+
$child->testIsCallable();
19+
$child->testIsCallable2();
20+
21+
?>
22+
--EXPECTF--
23+
Deprecated: Callables of the form ["ChildClass", "parent::testIsCallable"] are deprecated in %s on line %d
24+
bool(false)
25+
26+
Deprecated: Callables of the form ["ChildClass", "static::testIsCallable2"] are deprecated in %s on line %d
27+
bool(true)

Zend/tests/bug48899.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@ class ParentClass { }
77

88
class ChildClass extends ParentClass {
99
public function testIsCallable() {
10-
var_dump(is_callable(array($this, 'parent::testIsCallable')));
10+
var_dump(is_callable(array('ParentClass', 'testIsCallable')));
1111
}
1212
public function testIsCallable2() {
13-
var_dump(is_callable(array($this, 'static::testIsCallable2')));
13+
var_dump(is_callable(array('ChildClass', 'testIsCallable2')));
1414
}
1515
}
1616

Zend/tests/bug71622.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class Abc {
1717
public static function run() {
1818
$method = "foobar";
1919
getMethodName($method);
20-
var_dump(is_callable("self::$method"));
20+
var_dump(is_callable("Abc::$method"));
2121
self::$method();
2222
}
2323
}

Zend/tests/callable_self_parent_static_deprecation.phpt

Lines changed: 252 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -9,27 +9,52 @@ class A {
99
class B extends A {
1010
public function test() {
1111
// Different callables using self/parent/static
12-
echo "Test different callables\n";
13-
call_user_func("self::foo");
14-
call_user_func("parent::foo");
15-
call_user_func("static::foo");
16-
call_user_func(["self", "foo"]);
17-
call_user_func(["parent", "foo"]);
18-
call_user_func(["static", "foo"]);
19-
call_user_func(["B", "self::foo"]);
20-
call_user_func(["B", "parent::foo"]);
21-
call_user_func(["B", "static::foo"]);
22-
call_user_func(["B", "A::foo"]);
12+
$variants = [
13+
'"self::foo"' => "self::foo",
14+
'"parent::foo"' => "parent::foo",
15+
'"static::foo"' => "static::foo",
16+
'["self", "foo"]' => ["self", "foo"],
17+
'["parent", "foo"]' => ["parent", "foo"],
18+
'["static", "foo"]' => ["static", "foo"],
19+
'["B", "self::foo"]' => ["B", "self::foo"],
20+
'["B", "parent::foo"]' => ["B", "parent::foo"],
21+
'["B", "static::foo"]' => ["B", "static::foo"],
22+
'["B", "A::foo"]' => ["B", "A::foo"],
23+
'[$this, "self::foo"]' => [$this, "self::foo"],
24+
'[$this, "parent::foo"]' => [$this, "parent::foo"],
25+
'[$this, "static::foo"]' => [$this, "static::foo"],
26+
'[$this, "A::foo"]' => [$this, "A::foo"],
27+
];
28+
29+
echo "==> Test call_user_func\n";
30+
foreach ($variants as $description => $callable) {
31+
echo "$description\n";
32+
call_user_func($callable);
33+
}
34+
echo "\n==> Test call_user_func_array\n";
35+
foreach ($variants as $description => $callable) {
36+
echo "$description\n";
37+
call_user_func_array($callable, []);
38+
}
2339

2440
// Also applies to other things performing calls
25-
echo "Test array_map()\n";
26-
array_map("self::foo", [1]);
41+
echo "\n==> Test array_map\n";
42+
foreach ($variants as $description => $callable) {
43+
echo "$description\n";
44+
array_map($callable, [1]);
45+
}
2746

28-
echo "Test is_callable() -- should be silent\n";
29-
var_dump(is_callable("self::foo"));
47+
echo "\n==> Test is_callable()\n";
48+
foreach ($variants as $description => $callable) {
49+
echo "$description\n";
50+
var_dump(is_callable($callable));
51+
}
3052

31-
echo "Test callable type hint -- should be silent\n";
32-
$this->callableTypeHint("self::foo");
53+
echo "\n==> Test callable type hint\n";
54+
foreach ($variants as $description => $callable) {
55+
echo "$description\n";
56+
$this->callableTypeHint($callable);
57+
}
3358
}
3459

3560
public function callableTypeHint(callable $c) {}
@@ -40,30 +65,236 @@ $b->test();
4065

4166
?>
4267
--EXPECTF--
43-
Test different callables
68+
==> Test call_user_func
69+
"self::foo"
70+
71+
Deprecated: Use of "self" in callables is deprecated in %s on line %d
72+
"parent::foo"
73+
74+
Deprecated: Use of "parent" in callables is deprecated in %s on line %d
75+
"static::foo"
76+
77+
Deprecated: Use of "static" in callables is deprecated in %s on line %d
78+
["self", "foo"]
79+
80+
Deprecated: Use of "self" in callables is deprecated in %s on line %d
81+
["parent", "foo"]
82+
83+
Deprecated: Use of "parent" in callables is deprecated in %s on line %d
84+
["static", "foo"]
85+
86+
Deprecated: Use of "static" in callables is deprecated in %s on line %d
87+
["B", "self::foo"]
88+
89+
Deprecated: Callables of the form ["B", "self::foo"] are deprecated in %s on line %d
90+
["B", "parent::foo"]
91+
92+
Deprecated: Callables of the form ["B", "parent::foo"] are deprecated in %s on line %d
93+
["B", "static::foo"]
94+
95+
Deprecated: Callables of the form ["B", "static::foo"] are deprecated in %s on line %d
96+
["B", "A::foo"]
97+
98+
Deprecated: Callables of the form ["B", "A::foo"] are deprecated in %s on line %d
99+
[$this, "self::foo"]
100+
101+
Deprecated: Callables of the form ["B", "self::foo"] are deprecated in %s on line %d
102+
[$this, "parent::foo"]
103+
104+
Deprecated: Callables of the form ["B", "parent::foo"] are deprecated in %s on line %d
105+
[$this, "static::foo"]
106+
107+
Deprecated: Callables of the form ["B", "static::foo"] are deprecated in %s on line %d
108+
[$this, "A::foo"]
109+
110+
Deprecated: Callables of the form ["B", "A::foo"] are deprecated in %s on line %d
111+
112+
==> Test call_user_func_array
113+
"self::foo"
114+
115+
Deprecated: Use of "self" in callables is deprecated in %s on line %d
116+
"parent::foo"
117+
118+
Deprecated: Use of "parent" in callables is deprecated in %s on line %d
119+
"static::foo"
120+
121+
Deprecated: Use of "static" in callables is deprecated in %s on line %d
122+
["self", "foo"]
123+
124+
Deprecated: Use of "self" in callables is deprecated in %s on line %d
125+
["parent", "foo"]
126+
127+
Deprecated: Use of "parent" in callables is deprecated in %s on line %d
128+
["static", "foo"]
129+
130+
Deprecated: Use of "static" in callables is deprecated in %s on line %d
131+
["B", "self::foo"]
132+
133+
Deprecated: Callables of the form ["B", "self::foo"] are deprecated in %s on line %d
134+
["B", "parent::foo"]
135+
136+
Deprecated: Callables of the form ["B", "parent::foo"] are deprecated in %s on line %d
137+
["B", "static::foo"]
138+
139+
Deprecated: Callables of the form ["B", "static::foo"] are deprecated in %s on line %d
140+
["B", "A::foo"]
141+
142+
Deprecated: Callables of the form ["B", "A::foo"] are deprecated in %s on line %d
143+
[$this, "self::foo"]
144+
145+
Deprecated: Callables of the form ["B", "self::foo"] are deprecated in %s on line %d
146+
[$this, "parent::foo"]
147+
148+
Deprecated: Callables of the form ["B", "parent::foo"] are deprecated in %s on line %d
149+
[$this, "static::foo"]
150+
151+
Deprecated: Callables of the form ["B", "static::foo"] are deprecated in %s on line %d
152+
[$this, "A::foo"]
153+
154+
Deprecated: Callables of the form ["B", "A::foo"] are deprecated in %s on line %d
155+
156+
==> Test array_map
157+
"self::foo"
44158

45159
Deprecated: Use of "self" in callables is deprecated in %s on line %d
160+
"parent::foo"
46161

47162
Deprecated: Use of "parent" in callables is deprecated in %s on line %d
163+
"static::foo"
48164

49165
Deprecated: Use of "static" in callables is deprecated in %s on line %d
166+
["self", "foo"]
50167

51168
Deprecated: Use of "self" in callables is deprecated in %s on line %d
169+
["parent", "foo"]
52170

53171
Deprecated: Use of "parent" in callables is deprecated in %s on line %d
172+
["static", "foo"]
54173

55174
Deprecated: Use of "static" in callables is deprecated in %s on line %d
175+
["B", "self::foo"]
56176

57177
Deprecated: Callables of the form ["B", "self::foo"] are deprecated in %s on line %d
178+
["B", "parent::foo"]
58179

59180
Deprecated: Callables of the form ["B", "parent::foo"] are deprecated in %s on line %d
181+
["B", "static::foo"]
60182

61183
Deprecated: Callables of the form ["B", "static::foo"] are deprecated in %s on line %d
184+
["B", "A::foo"]
62185

63186
Deprecated: Callables of the form ["B", "A::foo"] are deprecated in %s on line %d
64-
Test array_map()
187+
[$this, "self::foo"]
188+
189+
Deprecated: Callables of the form ["B", "self::foo"] are deprecated in %s on line %d
190+
[$this, "parent::foo"]
191+
192+
Deprecated: Callables of the form ["B", "parent::foo"] are deprecated in %s on line %d
193+
[$this, "static::foo"]
194+
195+
Deprecated: Callables of the form ["B", "static::foo"] are deprecated in %s on line %d
196+
[$this, "A::foo"]
197+
198+
Deprecated: Callables of the form ["B", "A::foo"] are deprecated in %s on line %d
199+
200+
==> Test is_callable()
201+
"self::foo"
65202

66203
Deprecated: Use of "self" in callables is deprecated in %s on line %d
67-
Test is_callable() -- should be silent
68204
bool(true)
69-
Test callable type hint -- should be silent
205+
"parent::foo"
206+
207+
Deprecated: Use of "parent" in callables is deprecated in %s on line %d
208+
bool(true)
209+
"static::foo"
210+
211+
Deprecated: Use of "static" in callables is deprecated in %s on line %d
212+
bool(true)
213+
["self", "foo"]
214+
215+
Deprecated: Use of "self" in callables is deprecated in %s on line %d
216+
bool(true)
217+
["parent", "foo"]
218+
219+
Deprecated: Use of "parent" in callables is deprecated in %s on line %d
220+
bool(true)
221+
["static", "foo"]
222+
223+
Deprecated: Use of "static" in callables is deprecated in %s on line %d
224+
bool(true)
225+
["B", "self::foo"]
226+
227+
Deprecated: Callables of the form ["B", "self::foo"] are deprecated in %s on line %d
228+
bool(true)
229+
["B", "parent::foo"]
230+
231+
Deprecated: Callables of the form ["B", "parent::foo"] are deprecated in %s on line %d
232+
bool(true)
233+
["B", "static::foo"]
234+
235+
Deprecated: Callables of the form ["B", "static::foo"] are deprecated in %s on line %d
236+
bool(true)
237+
["B", "A::foo"]
238+
239+
Deprecated: Callables of the form ["B", "A::foo"] are deprecated in %s on line %d
240+
bool(true)
241+
[$this, "self::foo"]
242+
243+
Deprecated: Callables of the form ["B", "self::foo"] are deprecated in %s on line %d
244+
bool(true)
245+
[$this, "parent::foo"]
246+
247+
Deprecated: Callables of the form ["B", "parent::foo"] are deprecated in %s on line %d
248+
bool(true)
249+
[$this, "static::foo"]
250+
251+
Deprecated: Callables of the form ["B", "static::foo"] are deprecated in %s on line %d
252+
bool(true)
253+
[$this, "A::foo"]
254+
255+
Deprecated: Callables of the form ["B", "A::foo"] are deprecated in %s on line %d
256+
bool(true)
257+
258+
==> Test callable type hint
259+
"self::foo"
260+
261+
Deprecated: Use of "self" in callables is deprecated in %s on line %d
262+
"parent::foo"
263+
264+
Deprecated: Use of "parent" in callables is deprecated in %s on line %d
265+
"static::foo"
266+
267+
Deprecated: Use of "static" in callables is deprecated in %s on line %d
268+
["self", "foo"]
269+
270+
Deprecated: Use of "self" in callables is deprecated in %s on line %d
271+
["parent", "foo"]
272+
273+
Deprecated: Use of "parent" in callables is deprecated in %s on line %d
274+
["static", "foo"]
275+
276+
Deprecated: Use of "static" in callables is deprecated in %s on line %d
277+
["B", "self::foo"]
278+
279+
Deprecated: Callables of the form ["B", "self::foo"] are deprecated in %s on line %d
280+
["B", "parent::foo"]
281+
282+
Deprecated: Callables of the form ["B", "parent::foo"] are deprecated in %s on line %d
283+
["B", "static::foo"]
284+
285+
Deprecated: Callables of the form ["B", "static::foo"] are deprecated in %s on line %d
286+
["B", "A::foo"]
287+
288+
Deprecated: Callables of the form ["B", "A::foo"] are deprecated in %s on line %d
289+
[$this, "self::foo"]
290+
291+
Deprecated: Callables of the form ["B", "self::foo"] are deprecated in %s on line %d
292+
[$this, "parent::foo"]
293+
294+
Deprecated: Callables of the form ["B", "parent::foo"] are deprecated in %s on line %d
295+
[$this, "static::foo"]
296+
297+
Deprecated: Callables of the form ["B", "static::foo"] are deprecated in %s on line %d
298+
[$this, "A::foo"]
299+
300+
Deprecated: Callables of the form ["B", "A::foo"] are deprecated in %s on line %d

0 commit comments

Comments
 (0)