@@ -8,20 +8,34 @@ class Prototypes {
88
99 use Prototypeable;
1010
11+ /**
12+ * @var array[]
13+ */
1114 protected static array $ methods = [];
15+
16+ /**
17+ * @var Closure[]
18+ */
19+ protected static array $ static_methods = [];
20+
21+ /**
22+ * @var Closure[]
23+ */
1224 protected static array $ classes = [];
1325
14- public static function isPrototypeable (string $ class_name ): bool
15- {
16- return self ::$ classes [$ class_name ] ??= in_array (Prototypeable::class, self ::getClassTraits ($ class_name ));
17- }
1826
27+ /**
28+ * @param string $class_name
29+ * @param string $name
30+ * @param Closure $fun
31+ * @throws Exception
32+ */
1933 public static function addClassMethod (string $ class_name , string $ name , Closure $ fun ): void
2034 {
2135 if (self ::isPrototypeable ($ class_name )){
2236 if (!method_exists ($ class_name , $ name )){
2337 self ::$ methods [$ class_name ] ??= [];
24- if (!isset ( self ::$ methods [ $ class_name][ $ name] )){
38+ if (!self ::classHasPrototypeMethod ( $ class_name, $ name )){
2539 self ::$ methods [$ class_name ][$ name ] = $ fun ;
2640 }
2741 else {
@@ -37,6 +51,39 @@ public static function addClassMethod(string $class_name, string $name, Closure
3751 }
3852 }
3953
54+ /**
55+ * @param string $class_name
56+ * @param string $name
57+ * @param Closure $fun
58+ * @throws Exception
59+ */
60+ public static function addClassStaticMethod (string $ class_name , string $ name , Closure $ fun ): void
61+ {
62+ if (self ::isPrototypeable ($ class_name )){
63+ if (!method_exists ($ class_name , $ name )){
64+ self ::$ static_methods [$ class_name ] ??= [];
65+ if (!self ::classHasPrototypeMethod ($ class_name , $ name )){
66+ self ::$ static_methods [$ class_name ][$ name ] = $ fun ;
67+ }
68+ else {
69+ throw new Exception ("Invalid method name provided for class ' $ class_name': method ' $ name' is already a Prototype " );
70+ }
71+ }
72+ else {
73+ throw new Exception ("Invalid method name provided for class ' $ class_name': method ' $ name' already exists " );
74+ }
75+ }
76+ else {
77+ throw new Exception ("Invalid class provided: class ' $ class_name' is not Prototypeable " );
78+ }
79+ }
80+
81+ /**
82+ * @param object $obj
83+ * @param string $name
84+ * @param array $args
85+ * @return mixed
86+ */
4087 public static function call (object $ obj , string $ name , array $ args )
4188 {
4289 $ class_name = get_class ($ obj );
@@ -50,6 +97,49 @@ public static function call(object $obj, string $name, array $args)
5097 }
5198 }
5299
100+ /**
101+ * @param string $class_name
102+ * @param string $name
103+ * @param array $args
104+ * @return mixed
105+ */
106+ public static function callStatic (string $ class_name , string $ name , array $ args )
107+ {
108+ self ::$ static_methods [$ class_name ] ??= [];
109+ if (isset (self ::$ static_methods [$ class_name ][$ name ])){
110+ $ closure = self ::$ static_methods [$ class_name ][$ name ];
111+ return ($ closure ->bindTo (null , $ class_name ))(...$ args );
112+ }
113+ else {
114+ throw new Error ("Call to undefined static method $ class_name:: $ name() " );
115+ }
116+ }
117+
118+ /**
119+ * @param string $class_name
120+ * @return bool
121+ * @throws Exception
122+ */
123+ public static function isPrototypeable (string $ class_name ): bool
124+ {
125+ return self ::$ classes [$ class_name ] ??= in_array (Prototypeable::class, self ::getClassTraits ($ class_name ));
126+ }
127+
128+ /**
129+ * @param string $class_name
130+ * @param string $method_name
131+ * @return bool
132+ */
133+ public static function classHasPrototypeMethod (string $ class_name , string $ method_name ): bool
134+ {
135+ return isset (self ::$ methods [$ class_name ][$ method_name ]) || isset (self ::$ static_methods [$ class_name ][$ method_name ]);
136+ }
137+
138+ /**
139+ * @param string $class
140+ * @return array
141+ * @throws Exception
142+ */
53143 protected static function getClassTraits (string $ class ): array
54144 {
55145 if (!class_exists ($ class )){
@@ -68,6 +158,23 @@ protected static function getClassTraits(string $class): array
68158 return array_unique (array_values ($ traits ));
69159 }
70160
71- }
72161
73- ?>
162+ /**
163+ * Prototypes constructor that disallow instantiation
164+ * @throws Exception
165+ */
166+ public function __construct ()
167+ {
168+ throw new Exception (static ::class.' class can not be instantiated ' );
169+ }
170+
171+ /**
172+ * @param mixed ...$_
173+ * @throws Exception
174+ */
175+ final public static function addMethod (...$ _ ): void
176+ {
177+ throw new Exception ('Adding normal method to ' . static ::class . ' does not make sense. Did you mean addStaticMethod? ' );
178+ }
179+
180+ }
0 commit comments