Skip to content

Commit 1cdc02f

Browse files
committed
add static methods and fixes
1 parent 8d03660 commit 1cdc02f

File tree

2 files changed

+149
-11
lines changed

2 files changed

+149
-11
lines changed

src/Prototypeable.php

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,44 @@
66

77
trait Prototypeable{
88

9-
public function __call(string $name, array $args){
9+
/**
10+
* @param string $name
11+
* @param array $args
12+
* @return mixed
13+
*/
14+
public function __call(string $name, array $args)
15+
{
1016
return Prototypes::call($this, $name, $args);
1117
}
1218

13-
final public static function addMethod(string $name, Closure $fun){
14-
return Prototypes::addClassMethod(static::class, $name, $fun);
19+
/**
20+
* @param string $name
21+
* @param Closure $fun
22+
* @throws Exception
23+
*/
24+
final public static function addMethod(string $name, Closure $fun): void
25+
{
26+
Prototypes::addClassMethod(static::class, $name, $fun);
27+
}
28+
29+
/**
30+
* @param string $name
31+
* @param array $args
32+
* @return mixed
33+
*/
34+
public static function __callStatic(string $name, array $args)
35+
{
36+
return Prototypes::callStatic(static::class, $name, $args);
37+
}
38+
39+
/**
40+
* @param string $name
41+
* @param Closure $fun
42+
* @throws Exception
43+
*/
44+
final public static function addStaticMethod(string $name, Closure $fun): void
45+
{
46+
Prototypes::addClassStaticMethod(static::class, $name, $fun);
1547
}
1648
}
1749

18-
?>

src/Prototypes.php

Lines changed: 114 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)