Macroable.php 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130
  1. <?php
  2. declare(strict_types=1);
  3. /**
  4. * This file is part of Hyperf.
  5. *
  6. * @link https://www.hyperf.io
  7. * @document https://hyperf.wiki
  8. * @contact group@hyperf.io
  9. * @license https://github.com/hyperf/hyperf/blob/master/LICENSE
  10. */
  11. namespace Hyperf\Macroable;
  12. use BadMethodCallException;
  13. use Closure;
  14. use ReflectionClass;
  15. use ReflectionException;
  16. use ReflectionMethod;
  17. /**
  18. * This file come from illuminate/macroable,
  19. * thanks Laravel Team provide such a useful class.
  20. */
  21. trait Macroable
  22. {
  23. /**
  24. * The registered string macros.
  25. */
  26. protected static array $macros = [];
  27. /**
  28. * Dynamically handle calls to the class.
  29. *
  30. * @param string $method
  31. * @param array $parameters
  32. * @return mixed
  33. * @throws BadMethodCallException
  34. */
  35. public static function __callStatic($method, $parameters)
  36. {
  37. if (! static::hasMacro($method)) {
  38. throw new BadMethodCallException(sprintf(
  39. 'Method %s::%s does not exist.',
  40. static::class,
  41. $method
  42. ));
  43. }
  44. $macro = static::$macros[$method];
  45. if ($macro instanceof Closure) {
  46. $macro = $macro->bindTo(null, static::class);
  47. }
  48. return $macro(...$parameters);
  49. }
  50. /**
  51. * Dynamically handle calls to the class.
  52. *
  53. * @param string $method
  54. * @param array $parameters
  55. * @return mixed
  56. * @throws BadMethodCallException
  57. */
  58. public function __call($method, $parameters)
  59. {
  60. if (! static::hasMacro($method)) {
  61. throw new BadMethodCallException(sprintf(
  62. 'Method %s::%s does not exist.',
  63. static::class,
  64. $method
  65. ));
  66. }
  67. $macro = static::$macros[$method];
  68. if ($macro instanceof Closure) {
  69. $macro = $macro->bindTo($this, static::class);
  70. }
  71. return $macro(...$parameters);
  72. }
  73. /**
  74. * Register a custom macro.
  75. *
  76. * @param string $name
  77. * @param callable|object $macro
  78. *
  79. * @param-closure-this static $macro
  80. */
  81. public static function macro($name, $macro)
  82. {
  83. static::$macros[$name] = $macro;
  84. }
  85. /**
  86. * Mix another object into the class.
  87. *
  88. * @param object $mixin
  89. * @param bool $replace
  90. *
  91. * @throws ReflectionException
  92. */
  93. public static function mixin($mixin, $replace = true)
  94. {
  95. $methods = (new ReflectionClass($mixin))->getMethods(
  96. ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED
  97. );
  98. foreach ($methods as $method) {
  99. if ($replace || ! static::hasMacro($method->name)) {
  100. static::macro($method->name, $method->invoke($mixin));
  101. }
  102. }
  103. }
  104. /**
  105. * Checks if macro is registered.
  106. *
  107. * @param string $name
  108. * @return bool
  109. */
  110. public static function hasMacro($name)
  111. {
  112. return isset(static::$macros[$name]);
  113. }
  114. }