blob: 7e9fbd51a05fe1278528018df11b059b51201464 [file] [log] [blame]
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +02001<?php
2
3namespace Tightenco\Collect\Support\Traits;
4
5use BadMethodCallException;
6use Closure;
7use ReflectionClass;
8use ReflectionMethod;
9
10trait Macroable
11{
12 /**
13 * The registered string macros.
14 *
15 * @var array
16 */
17 protected static $macros = [];
18
19 /**
20 * Register a custom macro.
21 *
22 * @param string $name
23 * @param object|callable $macro
24 * @return void
25 */
26 public static function macro($name, $macro)
27 {
28 static::$macros[$name] = $macro;
29 }
30
31 /**
32 * Mix another object into the class.
33 *
34 * @param object $mixin
35 * @param bool $replace
36 * @return void
37 *
38 * @throws \ReflectionException
39 */
40 public static function mixin($mixin, $replace = true)
41 {
42 $methods = (new ReflectionClass($mixin))->getMethods(
43 ReflectionMethod::IS_PUBLIC | ReflectionMethod::IS_PROTECTED
44 );
45
46 foreach ($methods as $method) {
47 if ($replace || ! static::hasMacro($method->name)) {
48 $method->setAccessible(true);
49 static::macro($method->name, $method->invoke($mixin));
50 }
51 }
52 }
53
54 /**
55 * Checks if macro is registered.
56 *
57 * @param string $name
58 * @return bool
59 */
60 public static function hasMacro($name)
61 {
62 return isset(static::$macros[$name]);
63 }
64
65 /**
Matthias Andreas Benkard1ba53812022-12-27 17:32:58 +010066 * Flush the existing macros.
67 *
68 * @return void
69 */
70 public static function flushMacros()
71 {
72 static::$macros = [];
73 }
74
75 /**
Matthias Andreas Benkard7b2a3a12021-08-16 10:57:25 +020076 * Dynamically handle calls to the class.
77 *
78 * @param string $method
79 * @param array $parameters
80 * @return mixed
81 *
82 * @throws \BadMethodCallException
83 */
84 public static function __callStatic($method, $parameters)
85 {
86 if (! static::hasMacro($method)) {
87 throw new BadMethodCallException(sprintf(
88 'Method %s::%s does not exist.', static::class, $method
89 ));
90 }
91
92 $macro = static::$macros[$method];
93
94 if ($macro instanceof Closure) {
95 $macro = $macro->bindTo(null, static::class);
96 }
97
98 return $macro(...$parameters);
99 }
100
101 /**
102 * Dynamically handle calls to the class.
103 *
104 * @param string $method
105 * @param array $parameters
106 * @return mixed
107 *
108 * @throws \BadMethodCallException
109 */
110 public function __call($method, $parameters)
111 {
112 if (! static::hasMacro($method)) {
113 throw new BadMethodCallException(sprintf(
114 'Method %s::%s does not exist.', static::class, $method
115 ));
116 }
117
118 $macro = static::$macros[$method];
119
120 if ($macro instanceof Closure) {
121 $macro = $macro->bindTo($this, static::class);
122 }
123
124 return $macro(...$parameters);
125 }
126}