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