ReflectionConstant.php 4.9 KB

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