Skip to content

Commit eaf2b3c

Browse files
Emit deprecation warnings!
1 parent 009cdf1 commit eaf2b3c

File tree

11 files changed

+169
-7
lines changed

11 files changed

+169
-7
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
--TEST--
2+
#[\Deprecated]: Class alias - access a constant
3+
--FILE--
4+
<?php
5+
6+
#[ClassAlias('MyAlias', [new Deprecated()])]
7+
class Clazz {
8+
public const TEST = 1;
9+
}
10+
11+
var_dump(MyAlias::TEST);
12+
13+
?>
14+
--EXPECTF--
15+
Deprecated: Alias is deprecated in %s on line %d
16+
int(1)
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
--TEST--
2+
#[\Deprecated]: Class alias - access a static variable
3+
--FILE--
4+
<?php
5+
6+
#[ClassAlias('MyAlias', [new Deprecated()])]
7+
class Clazz {
8+
public static mixed $v = NULL;
9+
}
10+
11+
MyAlias::$v = true;
12+
13+
?>
14+
--EXPECTF--
15+
Deprecated: Alias is deprecated in %s on line %d
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
#[\Deprecated]: Class alias - call a static method
3+
--FILE--
4+
<?php
5+
6+
#[ClassAlias('MyAlias', [new Deprecated()])]
7+
class Clazz {
8+
public static function doNothing() {
9+
echo __METHOD__ . "\n";
10+
}
11+
}
12+
13+
MyAlias::doNothing();
14+
15+
?>
16+
--EXPECTF--
17+
Deprecated: Alias is deprecated in %s on line %d
18+
Clazz::doNothing
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--TEST--
2+
#[\Deprecated]: Class alias - all messages have details
3+
--FILE--
4+
<?php
5+
6+
#[ClassAlias('MyAlias', [new Deprecated("don't use the alias", "8.4")])]
7+
class Clazz {
8+
public const TEST = 1;
9+
10+
public static mixed $v = NULL;
11+
12+
public function __construct() {}
13+
14+
public static function doNothing() {}
15+
}
16+
17+
var_dump(MyAlias::TEST);
18+
MyAlias::$v = true;
19+
20+
$o = new MyAlias();
21+
22+
MyAlias::doNothing();
23+
24+
?>
25+
--EXPECTF--
26+
Deprecated: Alias is deprecated since 8.4, don't use the alias in %s on line %d
27+
int(1)
28+
29+
Deprecated: Alias is deprecated since 8.4, don't use the alias in %s on line %d
30+
31+
Deprecated: Alias is deprecated since 8.4, don't use the alias in %s on line %d
32+
33+
Deprecated: Alias is deprecated since 8.4, don't use the alias in %s on line %d
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
#[\Deprecated]: Class alias - use the constructor
3+
--FILE--
4+
<?php
5+
6+
#[ClassAlias('MyAlias', [new Deprecated()])]
7+
class Clazz {
8+
public function __construct() {
9+
echo __METHOD__ . "\n";
10+
}
11+
}
12+
13+
$o = new MyAlias();
14+
15+
?>
16+
--EXPECTF--
17+
Deprecated: Alias is deprecated in %s on line %d
18+
Clazz::__construct

Zend/zend_class_alias.c

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@
1717
*/
1818

1919
#include "zend_class_alias.h"
20+
#include "zend_errors.h"
21+
#include "zend_string.h"
22+
#include "zend.h"
2023

2124
zend_class_alias * zend_class_alias_init(zend_class_entry *ce) {
2225
zend_class_alias *alias = malloc(sizeof(zend_class_alias));
@@ -29,3 +32,19 @@ zend_class_alias * zend_class_alias_init(zend_class_entry *ce) {
2932

3033
return alias;
3134
}
35+
36+
ZEND_COLD zend_result ZEND_FASTCALL get_deprecation_suffix_from_attribute(HashTable *attributes, zend_class_entry* scope, zend_string **message_suffix);
37+
38+
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_class_alias(const zend_class_alias *alias) {
39+
zend_string *message_suffix = ZSTR_EMPTY_ALLOC();
40+
41+
if (get_deprecation_suffix_from_attribute(alias->attributes, NULL, &message_suffix) == FAILURE) {
42+
return;
43+
}
44+
45+
zend_error_unchecked(E_USER_DEPRECATED, "Alias is deprecated%S",
46+
message_suffix
47+
);
48+
49+
zend_string_release(message_suffix);
50+
}

Zend/zend_class_alias.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,5 +51,6 @@ typedef struct _zend_class_alias zend_class_alias;
5151

5252

5353
zend_class_alias * zend_class_alias_init(zend_class_entry *ce);
54+
ZEND_API ZEND_COLD void ZEND_FASTCALL zend_deprecated_class_alias(const zend_class_alias *alias);
5455

5556
#endif

Zend/zend_compile.c

Lines changed: 22 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "zend_call_stack.h"
3939
#include "zend_frameless_function.h"
4040
#include "zend_property_hooks.h"
41+
#include "zend_class_alias.h"
4142

4243
#define SET_NODE(target, src) do { \
4344
target ## _type = (src)->op_type; \
@@ -1875,8 +1876,23 @@ static bool zend_try_ct_eval_class_const(zval *zv, zend_string *class_name, zend
18751876
if (class_name_refers_to_active_ce(class_name, fetch_type)) {
18761877
cc = zend_hash_find_ptr(&CG(active_class_entry)->constants_table, name);
18771878
} else if (fetch_type == ZEND_FETCH_CLASS_DEFAULT && !(CG(compiler_options) & ZEND_COMPILE_NO_CONSTANT_SUBSTITUTION)) {
1878-
zend_class_entry *ce = zend_hash_find_ptr_lc(CG(class_table), class_name);
1879-
if (ce) {
1879+
zend_string *lc_key = zend_string_tolower(class_name);
1880+
zval *ce_or_alias = zend_hash_find(CG(class_table), lc_key);
1881+
zend_string_release(lc_key);
1882+
1883+
if (ce_or_alias) {
1884+
zend_class_entry *ce;
1885+
if (Z_TYPE_P(ce_or_alias) == IS_ALIAS_PTR) {
1886+
zend_class_alias *alias = Z_CLASS_ALIAS_P(ce_or_alias);
1887+
if (alias->alias_flags & ZEND_ACC_DEPRECATED) {
1888+
// Cannot evaluate at compile time
1889+
return 0;
1890+
}
1891+
ce = alias->ce;
1892+
} else {
1893+
ZEND_ASSERT(Z_TYPE_P(ce_or_alias) == IS_PTR);
1894+
ce = Z_PTR_P(ce_or_alias);
1895+
}
18801896
cc = zend_hash_find_ptr(&ce->constants_table, name);
18811897
} else {
18821898
return 0;
@@ -5340,7 +5356,10 @@ static void zend_compile_static_call(znode *result, zend_ast *ast, uint32_t type
53405356
zend_class_entry *ce = NULL;
53415357
if (opline->op1_type == IS_CONST) {
53425358
zend_string *lcname = Z_STR_P(CT_CONSTANT(opline->op1) + 1);
5343-
ce = zend_hash_find_ptr(CG(class_table), lcname);
5359+
zval *ce_or_alias = zend_hash_find(CG(class_table), lcname);
5360+
if (ce_or_alias) {
5361+
Z_CE_FROM_ZVAL_P(ce, ce_or_alias);
5362+
}
53445363
if (ce) {
53455364
if (zend_compile_ignore_class(ce, CG(active_op_array)->filename)) {
53465365
ce = NULL;

Zend/zend_execute.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1795,7 +1795,7 @@ ZEND_API ZEND_COLD void zend_wrong_string_offset_error(void)
17951795
zend_throw_error(NULL, "%s", msg);
17961796
}
17971797

1798-
ZEND_COLD static zend_result ZEND_FASTCALL get_deprecation_suffix_from_attribute(HashTable *attributes, zend_class_entry* scope, zend_string **message_suffix)
1798+
ZEND_COLD zend_result ZEND_FASTCALL get_deprecation_suffix_from_attribute(HashTable *attributes, zend_class_entry* scope, zend_string **message_suffix)
17991799
{
18001800
*message_suffix = ZSTR_EMPTY_ALLOC();
18011801

Zend/zend_execute_API.c

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1204,6 +1204,11 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string *
12041204
zend_string_release_ex(lc_name, 0);
12051205
}
12061206
Z_CE_FROM_ZVAL_P(ce, zv);
1207+
zend_class_alias *alias = NULL;
1208+
if (Z_TYPE_P(zv) == IS_ALIAS_PTR) {
1209+
ce_cache = 0;
1210+
alias = Z_CLASS_ALIAS_P(zv);
1211+
}
12071212
if (UNEXPECTED(!(ce->ce_flags & ZEND_ACC_LINKED))) {
12081213
if ((flags & ZEND_FETCH_CLASS_ALLOW_UNLINKED) ||
12091214
((flags & ZEND_FETCH_CLASS_ALLOW_NEARLY_LINKED) &&
@@ -1213,6 +1218,9 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string *
12131218
zend_hash_init(CG(unlinked_uses), 0, NULL, NULL, 0);
12141219
}
12151220
zend_hash_index_add_empty_element(CG(unlinked_uses), (zend_long)(uintptr_t)ce);
1221+
if (!(flags & ZEND_FETCH_CLASS_SILENT) && alias && (alias->alias_flags & ZEND_ACC_DEPRECATED)) {
1222+
zend_deprecated_class_alias(alias);
1223+
}
12161224
return ce;
12171225
}
12181226
return NULL;
@@ -1223,6 +1231,9 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string *
12231231
(!CG(in_compilation) || (ce->ce_flags & ZEND_ACC_IMMUTABLE))) {
12241232
SET_CE_CACHE(ce_cache, ce);
12251233
}
1234+
if (!(flags & ZEND_FETCH_CLASS_SILENT) && alias && (alias->alias_flags & ZEND_ACC_DEPRECATED)) {
1235+
zend_deprecated_class_alias(alias);
1236+
}
12261237
return ce;
12271238
}
12281239

@@ -1271,8 +1282,16 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string *
12711282
EG(lineno_override) = -1;
12721283
zend_exception_save();
12731284
zval *ce_zval = zend_autoload(autoload_name, lc_name);
1285+
zend_class_alias *alias = NULL;
12741286
if (ce_zval) {
1275-
ce = Z_PTR_P(ce_zval);
1287+
if (Z_TYPE_P(ce_zval) == IS_ALIAS_PTR) {
1288+
ce_cache = 0;
1289+
alias = Z_CLASS_ALIAS_P(ce_zval);
1290+
ce = alias->ce;
1291+
} else {
1292+
ZEND_ASSERT(Z_TYPE_P(ce_zval) == IS_PTR);
1293+
ce = Z_PTR_P(ce_zval);
1294+
}
12761295
}
12771296
zend_exception_restore();
12781297
EG(filename_override) = previous_filename;
@@ -1290,6 +1309,9 @@ ZEND_API zend_class_entry *zend_lookup_class_ex(zend_string *name, zend_string *
12901309
SET_CE_CACHE(ce_cache, ce);
12911310
}
12921311
}
1312+
if (!(flags & ZEND_FETCH_CLASS_SILENT) && alias && (alias->alias_flags & ZEND_ACC_DEPRECATED)) {
1313+
zend_deprecated_class_alias(alias);
1314+
}
12931315
return ce;
12941316
}
12951317
/* }}} */

ext/reflection/php_reflection.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7860,8 +7860,9 @@ ZEND_METHOD(ReflectionClassAlias, __construct)
78607860
ZEND_PARSE_PARAMETERS_END();
78617861

78627862
// First use zend_lookup_class() which will also take care of autoloading,
7863-
// but that will always return the underlying class entry
7864-
zend_class_entry *ce = zend_lookup_class(name);
7863+
// but that will always return the underlying class entry; don't complain
7864+
// about deprecations here
7865+
zend_class_entry *ce = zend_lookup_class_ex(name, NULL, ZEND_FETCH_CLASS_SILENT);
78657866
if (ce == NULL) {
78667867
if (!EG(exception)) {
78677868
zend_throw_exception_ex(reflection_exception_ptr, -1, "Class \"%s\" does not exist", ZSTR_VAL(name));

0 commit comments

Comments
 (0)