ReflectionConstant.php 4.9 KB

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