Skip to content

Commit 610bba8

Browse files
[8.4] Add polyfill for ReflectionConstant
1 parent c4ee386 commit 610bba8

File tree

4 files changed

+461
-0
lines changed

4 files changed

+461
-0
lines changed

README.md

+1
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ Polyfills are provided for:
7171
- the `array_find`, `array_find_key`, `array_any` and `array_all` functions introduced in PHP 8.4;
7272
- the `Deprecated` attribute introduced in PHP 8.4;
7373
- the `mb_trim`, `mb_ltrim` and `mb_rtrim` functions introduced in PHP 8.4;
74+
- the `ReflectionConstant` class introduced in PHP 8.4
7475
- the `CURL_HTTP_VERSION_3` and `CURL_HTTP_VERSION_3ONLY` constants introduced in PHP 8.4;
7576
- the `get_error_handler` and `get_exception_handler` functions introduced in PHP 8.5;
7677
- the `NoDiscard` attribute introduced in PHP 8.5;

src/Php84/README.md

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ This component provides features added to PHP 8.4 core:
99
- `CURL_HTTP_VERSION_3` and `CURL_HTTP_VERSION_3ONLY` constants
1010
- [`fpow`](https://wiki.php.net/rfc/raising_zero_to_power_of_negative_number)
1111
- [`mb_trim`, `mb_ltrim` and `mb_rtrim`](https://wiki.php.net/rfc/mb_trim)
12+
- [`ReflectionConstant`](https://github.com/php/php-src/pull/13669)
1213

1314
More information can be found in the
1415
[main Polyfill README](https://github.com/symfony/polyfill/blob/main/README.md).
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
<?php
2+
3+
/*
4+
* This file is part of the Symfony package.
5+
*
6+
* (c) Fabien Potencier <[email protected]>
7+
*
8+
* For the full copyright and license information, please view the LICENSE
9+
* file that was distributed with this source code.
10+
*/
11+
12+
/**
13+
* @author Daniel Scherzer <[email protected]>
14+
*/
15+
if (\PHP_VERSION_ID < 80400) {
16+
final class ReflectionConstant {
17+
18+
/**
19+
* @var string
20+
* @readonly
21+
*/
22+
public $name;
23+
24+
private $value;
25+
26+
/** @var bool */
27+
private $deprecated;
28+
29+
/** @var bool */
30+
private $persistent;
31+
32+
public function __construct(string $name)
33+
{
34+
if (!defined($name)) {
35+
throw new ReflectionException("Constant \"$name\" does not exist");
36+
}
37+
// ReflectionConstant cannot be used for class constants; constants
38+
// with 2 `:` or more in a row are prohibited via define()
39+
if (strpos($name, '::') !== false) {
40+
throw new ReflectionException("Constant \"$name\" does not exist");
41+
}
42+
$this->name = $name;
43+
$deprecated = false;
44+
$old = set_error_handler(
45+
static function (
46+
int $errno,
47+
string $errstr
48+
) use ($name, &$deprecated) {
49+
if ($errno === E_DEPRECATED
50+
&& $errstr === "Constant $name is deprecated"
51+
) {
52+
$deprecated = true;
53+
}
54+
return true;
55+
}
56+
);
57+
$this->value = constant($name);
58+
$this->deprecated = $deprecated;
59+
set_error_handler($old);
60+
61+
// A constant is persistent if provided by PHP itself rather than
62+
// being defined by users. If we got here, we know that it *is*
63+
// defined, so we just need to figure out if it is defined by the
64+
// user or not
65+
$allConstants = get_defined_constants(true);
66+
$userConstants = $allConstants['user'] ?? [];
67+
$key = ltrim($this->name, '\\');
68+
$this->persistent = !array_key_exists($key, $userConstants);
69+
}
70+
71+
public function getName(): string
72+
{
73+
return ltrim($this->name, '\\');
74+
}
75+
76+
public function getValue()
77+
{
78+
return $this->value;
79+
}
80+
81+
public function getNamespaceName(): string
82+
{
83+
$slashPos = strrpos($this->name, '\\');
84+
if ($slashPos === false) {
85+
return '';
86+
}
87+
return substr($this->name, 1, $slashPos - 1);
88+
}
89+
90+
public function getShortName(): string
91+
{
92+
$slashPos = strrpos($this->name, '\\');
93+
if ($slashPos === false) {
94+
return $this->name;
95+
}
96+
return substr($this->name, $slashPos + 1);
97+
}
98+
99+
public function isDeprecated(): bool
100+
{
101+
return $this->deprecated;
102+
}
103+
104+
public function __toString(): string
105+
{
106+
// Can't match the inclusion of `no_file_cache` but the rest is
107+
// possible to match
108+
$result = 'Constant [ ';
109+
if ($this->persistent || $this->deprecated) {
110+
$result .= '<';
111+
if ($this->persistent) {
112+
$result .= 'persistent';
113+
if ($this->deprecated) {
114+
$result .= ', ';
115+
}
116+
}
117+
if ($this->deprecated) {
118+
$result .= 'deprecated';
119+
}
120+
$result .= '> ';
121+
}
122+
// Cannot just use gettype() to match zend_zval_type_name()
123+
if (is_object($this->value)) {
124+
$result .= get_class($this->value);
125+
} elseif (is_bool($this->value)) {
126+
$result .= 'bool';
127+
} elseif (is_int($this->value)) {
128+
$result .= 'int';
129+
} elseif (is_float($this->value)) {
130+
$result .= 'float';
131+
} elseif (is_string($this->value)) {
132+
$result .= 'string';
133+
} elseif (is_resource($this->value)) {
134+
$result .= 'resource';
135+
} elseif ($this->value === null) {
136+
$result .= 'null';
137+
} else {
138+
// Reasonable fallback
139+
$result .= gettype($this->value);
140+
}
141+
$result .= ' ';
142+
$result .= $this->getName();
143+
$result .= ' ] { ';
144+
if (is_array($this->value)) {
145+
$result .= 'Array';
146+
} else {
147+
// This will throw an exception if the value is an object that
148+
// cannot be converted to string; that is expected and matches
149+
// the behavior of zval_get_string_func()
150+
$result .= (string)$this->value;
151+
}
152+
$result .= " }\n";
153+
return $result;
154+
}
155+
156+
public function __sleep(): array
157+
{
158+
throw new Exception("Serialization of 'ReflectionConstant' is not allowed");
159+
}
160+
161+
public function __wakeup(): void
162+
{
163+
throw new Exception("Unserialization of 'ReflectionConstant' is not allowed");
164+
}
165+
166+
}
167+
}

0 commit comments

Comments
 (0)