Skip to content

Commit bdb7da1

Browse files
committed
Add support for arrow function helpers
1 parent 67a203a commit bdb7da1

File tree

3 files changed

+84
-113
lines changed

3 files changed

+84
-113
lines changed

src/Exporter.php

+42-14
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,7 @@ final class Exporter
1313
public static function closure(\Closure $closure): string
1414
{
1515
$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);
1917
}
2018

2119
/**
@@ -38,20 +36,50 @@ public static function helpers(Context $context): string
3836
return "[$ret]";
3937
}
4038

41-
public static function getFunctionCode(\ReflectionFunction $refobj): string
39+
public static function getClosureSource(\ReflectionFunction $fn): string
4240
{
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 = '';
4647

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+
}
4959

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+
}
5482

55-
return substr($lines, $spos, $epos - $spos);
83+
return $code;
5684
}
5785
}

tests/ExporterTest.php

+7-2
Original file line numberDiff line numberDiff line change
@@ -9,8 +9,13 @@ class ExporterTest extends TestCase
99
{
1010
public function testClosure(): void
1111
{
12-
$this->assertSame('function($a) { return 1; }', Exporter::closure(
13-
function ($a) { return 1; },
12+
$this->assertSame('function ($a) { return 1 + $a; }', Exporter::closure(
13+
function ($a) { return 1 + $a; },
14+
));
15+
16+
$this->assertSame('fn() => 1 + 1', Exporter::closure(fn() => 1 + 1));
17+
$this->assertSame('fn(int $a) => $a * 2', Exporter::closure(
18+
fn(int $a) => $a * 2,
1419
));
1520
}
1621
}

0 commit comments

Comments
 (0)