@@ -13,9 +13,7 @@ final class Exporter
13
13
public static function closure (\Closure $ closure ): string
14
14
{
15
15
$ ref = new \ReflectionFunction ($ closure );
16
- $ code = static ::getFunctionCode ($ ref );
17
-
18
- return preg_replace ('/^.*?function(\s+[^\s \\(]+?)?\s* \\((.+) \\}.*?\s*$/s ' , 'function($2} ' , $ code );
16
+ return static ::getClosureSource ($ ref );
19
17
}
20
18
21
19
/**
@@ -38,20 +36,50 @@ public static function helpers(Context $context): string
38
36
return "[ $ ret] " ;
39
37
}
40
38
41
- public static function getFunctionCode (\ReflectionFunction $ refobj ): string
39
+ public static function getClosureSource (\ReflectionFunction $ fn ): string
42
40
{
43
- $ fname = $ refobj ->getFileName ();
44
- $ lines = file_get_contents ($ fname );
45
- $ file = new \SplFileObject ($ fname );
41
+ $ fileContents = file_get_contents ($ fn ->getFileName ());
42
+ $ startLine = $ fn ->getStartLine ();
43
+ $ endLine = $ fn ->getEndLine ();
44
+ $ enteredFnToken = null ;
45
+ $ depth = 0 ;
46
+ $ code = '' ;
46
47
47
- $ start = $ refobj ->getStartLine () - 1 ;
48
- $ end = $ refobj ->getEndLine ();
48
+ foreach (\PhpToken::tokenize ($ fileContents ) as $ token ) {
49
+ if ($ token ->line < $ startLine ) {
50
+ continue ;
51
+ } elseif ($ token ->line > $ endLine ) {
52
+ break ;
53
+ } elseif (!$ enteredFnToken ) {
54
+ if ($ token ->id !== T_FUNCTION && $ token ->id !== T_FN ) {
55
+ continue ;
56
+ }
57
+ $ enteredFnToken = $ token ;
58
+ }
49
59
50
- $ file ->seek ($ start );
51
- $ spos = $ file ->ftell ();
52
- $ file ->seek ($ end );
53
- $ epos = $ file ->ftell ();
60
+ $ name = $ token ->getTokenName ();
61
+
62
+ if (in_array ($ name , ['( ' , '[ ' , '{ ' , 'T_CURLY_OPEN ' ])) {
63
+ $ depth ++;
64
+ } elseif (in_array ($ name , [') ' , '] ' , '} ' ])) {
65
+ if ($ depth === 0 && $ enteredFnToken ->id === T_FN ) {
66
+ return rtrim ($ code );
67
+ }
68
+ $ depth --;
69
+ }
70
+
71
+ if ($ depth === 0 ) {
72
+ if ($ enteredFnToken ->id === T_FUNCTION && $ name === '} ' ) {
73
+ $ code .= $ token ->text ;
74
+ return $ code ;
75
+ } elseif ($ enteredFnToken ->id === T_FN && in_array ($ name , ['; ' , ', ' ])) {
76
+ return $ code ;
77
+ }
78
+ }
79
+
80
+ $ code .= $ token ->text ;
81
+ }
54
82
55
- return substr ( $ lines , $ spos , $ epos - $ spos ) ;
83
+ return $ code ;
56
84
}
57
85
}
0 commit comments