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: } elseif ($callable instanceof \Closure) {
31: return $callable;
32: }
33:
34: self::check($callable, TRUE);
35: $_callable_ = $callable;
36: return function () use ($_callable_) {
37: Callback::check($_callable_);
38: return call_user_func_array($_callable_, func_get_args());
39: };
40: }
41:
42:
43: 44: 45: 46:
47: public static function invoke($callable)
48: {
49: self::check($callable);
50: return call_user_func_array($callable, array_slice(func_get_args(), 1));
51: }
52:
53:
54: 55: 56: 57:
58: public static function invokeArgs($callable, array $args = array())
59: {
60: self::check($callable);
61: return call_user_func_array($callable, $args);
62: }
63:
64:
65: 66: 67: 68: 69: 70:
71: public static function invokeSafe($function, array $args, $onError)
72: {
73: $prev = set_error_handler(function ($severity, $message, $file, $line, $context = NULL, $stack = NULL) use ($onError, & $prev, $function) {
74: if ($file === '' && defined('HHVM_VERSION')) {
75: $file = $stack[1]['file'];
76: }
77: if ($file === __FILE__) {
78: $msg = preg_replace("#^$function\(.*?\): #", '', $message);
79: if ($onError($msg, $severity) !== FALSE) {
80: return;
81: }
82: }
83: return $prev ? call_user_func_array($prev, func_get_args()) : FALSE;
84: });
85:
86: try {
87: $res = call_user_func_array($function, $args);
88: restore_error_handler();
89: return $res;
90:
91: } catch (\Throwable $e) {
92: restore_error_handler();
93: throw $e;
94: } catch (\Exception $e) {
95: restore_error_handler();
96: throw $e;
97: }
98: }
99:
100:
101: 102: 103:
104: public static function check($callable, $syntax = FALSE)
105: {
106: if (!is_callable($callable, $syntax)) {
107: throw new Nette\InvalidArgumentException($syntax
108: ? 'Given value is not a callable type.'
109: : sprintf("Callback '%s' is not callable.", self::toString($callable))
110: );
111: }
112: return $callable;
113: }
114:
115:
116: 117: 118:
119: public static function toString($callable)
120: {
121: if ($callable instanceof \Closure) {
122: if ($inner = self::unwrap($callable)) {
123: return '{closure ' . self::toString($inner) . '}';
124: }
125: return '{closure}';
126: } elseif (is_string($callable) && $callable[0] === "\0") {
127: return '{lambda}';
128: } else {
129: is_callable($callable, TRUE, $textual);
130: return $textual;
131: }
132: }
133:
134:
135: 136: 137:
138: public static function toReflection($callable)
139: {
140: if ($callable instanceof \Closure && $inner = self::unwrap($callable)) {
141: $callable = $inner;
142: } elseif ($callable instanceof Nette\Callback) {
143: $callable = $callable->getNative();
144: }
145:
146: $class = class_exists('Nette\Reflection\Method') ? 'Nette\Reflection\Method' : 'ReflectionMethod';
147: if (is_string($callable) && strpos($callable, '::')) {
148: return new $class($callable);
149: } elseif (is_array($callable)) {
150: return new $class($callable[0], $callable[1]);
151: } elseif (is_object($callable) && !$callable instanceof \Closure) {
152: return new $class($callable, '__invoke');
153: } else {
154: $class = class_exists('Nette\Reflection\GlobalFunction') ? 'Nette\Reflection\GlobalFunction' : 'ReflectionFunction';
155: return new $class($callable);
156: }
157: }
158:
159:
160: 161: 162:
163: public static function isStatic($callable)
164: {
165: return is_array($callable) ? is_string($callable[0]) : is_string($callable);
166: }
167:
168:
169: 170: 171: 172: 173:
174: public static function unwrap(\Closure $closure)
175: {
176: $rm = new \ReflectionFunction($closure);
177: $vars = $rm->getStaticVariables();
178: return isset($vars['_callable_']) ? $vars['_callable_'] : NULL;
179: }
180:
181: }
182: