-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathreflection.php
More file actions
137 lines (117 loc) · 5.02 KB
/
Copy pathreflection.php
File metadata and controls
137 lines (117 loc) · 5.02 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
<?php
declare(strict_types=1);
namespace betterphp\utils;
class reflection {
/**
* Used by the below functions to find properties and methods
*
* @param string $class_name The name of the starting class
* @param string $name The name of the thing being searched for
* @param string $method_name The method to be called for the list to search in
*
* @return string The name of the class
*/
private static function resolve_class(string $class_name, string $name, string $method_name): string {
$class = new \ReflectionClass($class_name);
do {
foreach ($class->$method_name() as $compare) {
if ($compare->class === $class->getName() && $compare->name === $name) {
return $class->getName();
}
}
$class = $class->getParentClass();
} while ($class);
throw new \Exception("Unable to find class for {$name}");
}
/**
* Search for the class name that a property is defined in. This is useful
* as the reflection API needs that and not the class of the actual object.
*
* @param string $class_name The name of the starting class
* @param string $property_name The name of the property to search for
*
* @return string The name of the owner class
*/
private static function resolve_property_class(string $class_name, string $property_name): string {
return static::resolve_class($class_name, $property_name, 'getProperties');
}
/**
* Search for the class name that a method is defined in. This is useful
* as the reflection API needs that and not the class of the actual object.
*
* @param string $class_name The name of the starting class
* @param string $method_name The name of the method to search for
*
* @return string The name of the owner class
*/
private static function resolve_method_class(string $class_name, string $method_name): string {
return static::resolve_class($class_name, $method_name, 'getMethods');
}
/**
* Gets the value of an object property
*
* @param mixed $object The object to get the value from or the class name for static properties
* @param string $property_name The name of the property
*
* @return mixed The value
*/
public static function get_property($object, string $property_name) {
$class_name = (is_object($object)) ? get_class($object) : $object;
$class_name = static::resolve_property_class($class_name, $property_name);
$property = new \ReflectionProperty($class_name, $property_name);
$property->setAccessible(true);
if (is_object($object)) {
return $property->getValue($object);
} else {
$class = $property->getDeclaringClass();
$values = $class->getStaticProperties();
return $values[$property_name];
}
}
/**
* Sets the value of an object property
*
* @param mixed $object The object to update or the name of the class for static properties
* @param string $property_name The name of the property
* @param mixed $value The new value to set
*
* @return void
*/
public static function set_property($object, string $property_name, $value) {
$class_name = (is_object($object)) ? get_class($object) : $object;
$class_name = static::resolve_property_class($class_name, $property_name);
$property = new \ReflectionProperty($class_name, $property_name);
$property->setAccessible(true);
$property->setValue((is_object($object)) ? $object : null, $value);
}
/**
* Gets the closure of a method that can then be called or passed to a function as a callback
*
* @param mixed $object The object or class name that the method is from
* @param string $method_name The name of the method
*
* @return \Closure The function
*/
public static function get_method($object, string $method_name): \Closure {
$class_name = (is_object($object)) ? get_class($object) : $object;
$class_name = static::resolve_method_class($class_name, $method_name);
$method = new \ReflectionMethod($class_name, $method_name);
$method->setAccessible(true);
$target = (is_object($object)) ? $object : null;
return $method->getClosure($target);
}
/**
* Executes a method on a class or object. If a string is given for the first
* parameter then it will be treated as a class name and the method will be
* called statically.
*
* @param mixed $object The object or class name that the function is from
* @param string $method_name The name of the method to be called
* @param array $args The arguments to pass to the function
*
* @return mixed The value returned by the function
*/
public static function call_method($object, string $method_name, array $args = []) {
return static::get_method($object, $method_name)(...$args);
}
}