1: <?php
2:
3: 4: 5: 6:
7:
8: namespace Nette\Utils;
9:
10: use Nette;
11:
12:
13: 14: 15: 16: 17:
18: class Callback
19: {
20:
21: 22: 23: 24: 25:
26: public static function closure($callable, $m = NULL)
27: {
28: if ($m !== NULL) {
29: $callable = array($callable, $m);
30:
31: } elseif (is_string($callable) && count($tmp = explode('::', $callable)) === 2) {
32: $callable = $tmp;
33:
34: } elseif ($callable instanceof \Closure) {
35: return $callable;
36:
37: } elseif (is_object($callable)) {
38: $callable = array($callable, '__invoke');
39: }
40:
41: if (PHP_VERSION_ID >= 50400) {
42: if (is_string($callable) && function_exists($callable)) {
43: $r = new \ReflectionFunction($callable);
44: return $r->getClosure();
45:
46: } elseif (is_array($callable) && method_exists($callable[0], $callable[1])) {
47: $r = new \ReflectionMethod($callable[0], $callable[1]);
48: return $r->getClosure($callable[0]);
49: }
50: }
51:
52: self::check($callable);
53: $_callable_ = $callable;
54: return function() use ($_callable_) {
55: return call_user_func_array($_callable_, func_get_args());
56: };
57: }
58:
59:
60: 61: 62: 63:
64: public static function invoke($callable)
65: {
66: self::check($callable);
67: return call_user_func_array($callable, array_slice(func_get_args(), 1));
68: }
69:
70:
71: 72: 73: 74:
75: public static function invokeArgs($callable, array $args = array())
76: {
77: self::check($callable);
78: return call_user_func_array($callable, $args);
79: }
80:
81:
82: 83: 84: 85:
86: public static function invokeSafe($function, array $args, $onError)
87: {
88: $prev = set_error_handler(function($severity, $message, $file) use ($onError, & $prev) {
89: if ($file === __FILE__ && $onError($message, $severity) !== FALSE) {
90: return;
91: } elseif ($prev) {
92: return call_user_func_array($prev, func_get_args());
93: }
94: return FALSE;
95: });
96:
97: try {
98: $res = call_user_func_array($function, $args);
99: restore_error_handler();
100: return $res;
101:
102: } catch (\Exception $e) {
103: restore_error_handler();
104: throw $e;
105: }
106: }
107:
108:
109: 110: 111:
112: public static function check($callable, $syntax = FALSE)
113: {
114: if (!is_callable($callable, $syntax)) {
115: throw new Nette\InvalidArgumentException($syntax
116: ? 'Given value is not a callable type.'
117: : sprintf("Callback '%s' is not callable.", self::toString($callable))
118: );
119: }
120: return $callable;
121: }
122:
123:
124: 125: 126:
127: public static function toString($callable)
128: {
129: if ($callable instanceof \Closure) {
130: $inner = self::unwrap($callable);
131: return '{closure' . ($inner instanceof \Closure ? '}' : ' ' . self::toString($inner) . '}');
132: } elseif (is_string($callable) && $callable[0] === "\0") {
133: return '{lambda}';
134: } else {
135: is_callable($callable, TRUE, $textual);
136: return $textual;
137: }
138: }
139:
140:
141: 142: 143:
144: public static function toReflection($callable)
145: {
146: if ($callable instanceof \Closure) {
147: $callable = self::unwrap($callable);
148: } elseif ($callable instanceof Nette\Callback) {
149: $callable = $callable->getNative();
150: }
151:
152: $class = class_exists('Nette\Reflection\Method') ? 'Nette\Reflection\Method' : 'ReflectionMethod';
153: if (is_string($callable) && strpos($callable, '::')) {
154: return new $class($callable);
155: } elseif (is_array($callable)) {
156: return new $class($callable[0], $callable[1]);
157: } elseif (is_object($callable) && !$callable instanceof \Closure) {
158: return new $class($callable, '__invoke');
159: } else {
160: $class = class_exists('Nette\Reflection\GlobalFunction') ? 'Nette\Reflection\GlobalFunction' : 'ReflectionFunction';
161: return new $class($callable);
162: }
163: }
164:
165:
166: 167: 168:
169: public static function isStatic($callable)
170: {
171: return is_array($callable) ? is_string($callable[0]) : is_string($callable);
172: }
173:
174:
175: 176: 177: 178: 179:
180: public static function unwrap(\Closure $closure)
181: {
182: $r = new \ReflectionFunction($closure);
183: if (substr($r->getName(), -1) === '}') {
184: $vars = $r->getStaticVariables();
185: return isset($vars['_callable_']) ? $vars['_callable_'] : $closure;
186:
187: } elseif ($obj = $r->getClosureThis()) {
188: return array($obj, $r->getName());
189:
190: } elseif ($class = $r->getClosureScopeClass()) {
191: return array($class->getName(), $r->getName());
192:
193: } else {
194: return $r->getName();
195: }
196: }
197:
198: }
199: