ReflectionConstant.php 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157
  1. <?php
  2. /*
  3. * This file is part of the Symfony package.
  4. *
  5. * (c) Fabien Potencier <fabien@symfony.com>
  6. *
  7. * For the full copyright and license information, please view the LICENSE
  8. * file that was distributed with this source code.
  9. */
  10. if (\PHP_VERSION_ID < 80400) {
  11. // @author Daniel Scherzer <daniel.e.scherzer@gmail.com>
  12. final class ReflectionConstant
  13. {
  14. /**
  15. * @var string
  16. *
  17. * @readonly
  18. */
  19. public $name;
  20. private $value;
  21. private $deprecated;
  22. private $persistent;
  23. private static $persistentConstants = [];
  24. public function __construct(string $name)
  25. {
  26. if (!defined($name) || false !== strpos($name, '::')) {
  27. throw new ReflectionException("Constant \"$name\" does not exist");
  28. }
  29. $this->name = ltrim($name, '\\');
  30. $deprecated = false;
  31. $eh = set_error_handler(static function ($type, $msg, $file, $line) use ($name, &$deprecated, &$eh) {
  32. if (\E_DEPRECATED === $type && "Constant $name is deprecated" === $msg) {
  33. return $deprecated = true;
  34. }
  35. return $eh && $eh($type, $msg, $file, $line);
  36. });
  37. try {
  38. $this->value = constant($name);
  39. $this->deprecated = $deprecated;
  40. } finally {
  41. restore_error_handler();
  42. }
  43. }
  44. public function getName(): string
  45. {
  46. return $this->name;
  47. }
  48. public function getValue()
  49. {
  50. return $this->value;
  51. }
  52. public function getNamespaceName(): string
  53. {
  54. if (false === $slashPos = strrpos($this->name, '\\')) {
  55. return '';
  56. }
  57. return substr($this->name, 0, $slashPos);
  58. }
  59. public function getShortName(): string
  60. {
  61. if (false === $slashPos = strrpos($this->name, '\\')) {
  62. return $this->name;
  63. }
  64. return substr($this->name, $slashPos + 1);
  65. }
  66. public function isDeprecated(): bool
  67. {
  68. return $this->deprecated;
  69. }
  70. public function __toString(): string
  71. {
  72. // A constant is persistent if provided by PHP itself rather than
  73. // being defined by users. If we got here, we know that it *is*
  74. // defined, so we just need to figure out if it is defined by the
  75. // user or not
  76. if (!self::$persistentConstants) {
  77. $persistentConstants = get_defined_constants(true);
  78. unset($persistentConstants['user']);
  79. foreach ($persistentConstants as $constants) {
  80. self::$persistentConstants += $constants;
  81. }
  82. }
  83. $persistent = array_key_exists($this->name, self::$persistentConstants);
  84. // Can't match the inclusion of `no_file_cache` but the rest is
  85. // possible to match
  86. $result = 'Constant [ ';
  87. if ($persistent || $this->deprecated) {
  88. $result .= '<';
  89. if ($persistent) {
  90. $result .= 'persistent';
  91. if ($this->deprecated) {
  92. $result .= ', ';
  93. }
  94. }
  95. if ($this->deprecated) {
  96. $result .= 'deprecated';
  97. }
  98. $result .= '> ';
  99. }
  100. // Cannot just use gettype() to match zend_zval_type_name()
  101. if (is_object($this->value)) {
  102. $result .= \PHP_VERSION_ID >= 80000 ? get_debug_type($this->value) : gettype($this->value);
  103. } elseif (is_bool($this->value)) {
  104. $result .= 'bool';
  105. } elseif (is_int($this->value)) {
  106. $result .= 'int';
  107. } elseif (is_float($this->value)) {
  108. $result .= 'float';
  109. } elseif (null === $this->value) {
  110. $result .= 'null';
  111. } else {
  112. $result .= gettype($this->value);
  113. }
  114. $result .= ' ';
  115. $result .= $this->name;
  116. $result .= ' ] { ';
  117. if (is_array($this->value)) {
  118. $result .= 'Array';
  119. } else {
  120. // This will throw an exception if the value is an object that
  121. // cannot be converted to string; that is expected and matches
  122. // the behavior of zval_get_string_func()
  123. $result .= (string) $this->value;
  124. }
  125. $result .= " }\n";
  126. return $result;
  127. }
  128. public function __sleep(): array
  129. {
  130. throw new Exception("Serialization of 'ReflectionConstant' is not allowed");
  131. }
  132. public function __wakeup(): void
  133. {
  134. throw new Exception("Unserialization of 'ReflectionConstant' is not allowed");
  135. }
  136. }
  137. }