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__ && $onError(str_replace("$function(): ", '', $message), $severity) !== FALSE) {
92: return;
93: } elseif ($prev) {
94: return call_user_func_array($prev, func_get_args());
95: }
96: return FALSE;
97: });
98:
99: try {
100: $res = call_user_func_array($function, $args);
101: restore_error_handler();
102: return $res;
103:
104: } catch (\Exception $e) {
105: restore_error_handler();
106: throw $e;
107: }
108: }
109:
110:
111: 112: 113:
114: public static function check($callable, $syntax = FALSE)
115: {
116: if (!is_callable($callable, $syntax)) {
117: throw new Nette\InvalidArgumentException($syntax
118: ? 'Given value is not a callable type.'
119: : sprintf("Callback '%s' is not callable.", self::toString($callable))
120: );
121: }
122: return $callable;
123: }
124:
125:
126: 127: 128:
129: public static function toString($callable)
130: {
131: if ($callable instanceof \Closure) {
132: $inner = self::unwrap($callable);
133: return '{closure' . ($inner instanceof \Closure ? '}' : ' ' . self::toString($inner) . '}');
134: } elseif (is_string($callable) && $callable[0] === "\0") {
135: return '{lambda}';
136: } else {
137: is_callable($callable, TRUE, $textual);
138: return $textual;
139: }
140: }
141:
142:
143: 144: 145:
146: public static function toReflection($callable)
147: {
148: if ($callable instanceof \Closure) {
149: $callable = self::unwrap($callable);
150: } elseif ($callable instanceof Nette\Callback) {
151: $callable = $callable->getNative();
152: }
153:
154: $class = class_exists('Nette\Reflection\Method') ? 'Nette\Reflection\Method' : 'ReflectionMethod';
155: if (is_string($callable) && strpos($callable, '::')) {
156: return new $class($callable);
157: } elseif (is_array($callable)) {
158: return new $class($callable[0], $callable[1]);
159: } elseif (is_object($callable) && !$callable instanceof \Closure) {
160: return new $class($callable, '__invoke');
161: } else {
162: $class = class_exists('Nette\Reflection\GlobalFunction') ? 'Nette\Reflection\GlobalFunction' : 'ReflectionFunction';
163: return new $class($callable);
164: }
165: }
166:
167:
168: 169: 170:
171: public static function isStatic($callable)
172: {
173: return is_array($callable) ? is_string($callable[0]) : is_string($callable);
174: }
175:
176:
177: 178: 179: 180: 181:
182: public static function unwrap(\Closure $closure)
183: {
184: $r = new \ReflectionFunction($closure);
185: if (substr($r->getName(), -1) === '}') {
186: $vars = $r->getStaticVariables();
187: return isset($vars['_callable_']) ? $vars['_callable_'] : $closure;
188:
189: } elseif ($obj = $r->getClosureThis()) {
190: return array($obj, $r->getName());
191:
192: } elseif ($class = $r->getClosureScopeClass()) {
193: return array($class->getName(), $r->getName());
194:
195: } else {
196: return $r->getName();
197: }
198: }
199:
200: }
201: