Skip to content

Commit e2b37fc

Browse files
committed
formatting
1 parent 9448a5a commit e2b37fc

File tree

2 files changed

+223
-138
lines changed

2 files changed

+223
-138
lines changed

src/Support/ReflectionClosure.php

Lines changed: 169 additions & 138 deletions
Original file line numberDiff line numberDiff line change
@@ -298,20 +298,14 @@ public function getCode()
298298
case '}':
299299
$code .= '}';
300300
if (--$open === 0 && ! $isShortClosure) {
301-
$candidates[] = [
302-
'code' => $code,
303-
'use' => $use,
304-
'isShortClosure' => $isShortClosure,
305-
'isUsingThisObject' => $isUsingThisObject,
306-
'isUsingScope' => $isUsingScope,
307-
];
308-
$code = '';
309-
$state = 'start';
310-
$open = 0;
311-
$use = [];
312-
$isShortClosure = false;
313-
$isUsingThisObject = false;
314-
$isUsingScope = false;
301+
$reset = $this->collectCandidate($candidates, $code, $use, $isShortClosure, $isUsingThisObject, $isUsingScope);
302+
$code = $reset['code'];
303+
$state = $reset['state'];
304+
$open = $reset['open'];
305+
$use = $reset['use'];
306+
$isShortClosure = $reset['isShortClosure'];
307+
$isUsingThisObject = $reset['isUsingThisObject'];
308+
$isUsingScope = $reset['isUsingScope'];
315309
} elseif ($inside_structure) {
316310
$inside_structure = ! ($open === $inside_structure_mark);
317311
}
@@ -327,20 +321,14 @@ public function getCode()
327321
case ']':
328322
if ($isShortClosure) {
329323
if ($open === 0) {
330-
$candidates[] = [
331-
'code' => $code,
332-
'use' => $use,
333-
'isShortClosure' => $isShortClosure,
334-
'isUsingThisObject' => $isUsingThisObject,
335-
'isUsingScope' => $isUsingScope,
336-
];
337-
$code = '';
338-
$state = 'start';
339-
$open = 0;
340-
$use = [];
341-
$isShortClosure = false;
342-
$isUsingThisObject = false;
343-
$isUsingScope = false;
324+
$reset = $this->collectCandidate($candidates, $code, $use, $isShortClosure, $isUsingThisObject, $isUsingScope);
325+
$code = $reset['code'];
326+
$state = $reset['state'];
327+
$open = $reset['open'];
328+
$use = $reset['use'];
329+
$isShortClosure = $reset['isShortClosure'];
330+
$isUsingThisObject = $reset['isUsingThisObject'];
331+
$isUsingScope = $reset['isUsingScope'];
344332
continue 3;
345333
}
346334
$open--;
@@ -350,20 +338,14 @@ public function getCode()
350338
case ',':
351339
case ';':
352340
if ($isShortClosure && $open === 0) {
353-
$candidates[] = [
354-
'code' => $code,
355-
'use' => $use,
356-
'isShortClosure' => $isShortClosure,
357-
'isUsingThisObject' => $isUsingThisObject,
358-
'isUsingScope' => $isUsingScope,
359-
];
360-
$code = '';
361-
$state = 'start';
362-
$open = 0;
363-
$use = [];
364-
$isShortClosure = false;
365-
$isUsingThisObject = false;
366-
$isUsingScope = false;
341+
$reset = $this->collectCandidate($candidates, $code, $use, $isShortClosure, $isUsingThisObject, $isUsingScope);
342+
$code = $reset['code'];
343+
$state = $reset['state'];
344+
$open = $reset['open'];
345+
$use = $reset['use'];
346+
$isShortClosure = $reset['isShortClosure'];
347+
$isUsingThisObject = $reset['isUsingThisObject'];
348+
$isUsingScope = $reset['isUsingScope'];
367349
continue 3;
368350
}
369351
$code .= $token[0];
@@ -713,16 +695,6 @@ public function getCode()
713695
}
714696
}
715697

716-
if ($isShortClosure) {
717-
$this->useVariables = $this->getStaticVariables();
718-
} else {
719-
$this->useVariables = empty($use) ? $use : array_intersect_key($this->getStaticVariables(), array_flip($use));
720-
}
721-
722-
$this->isShortClosure = $isShortClosure;
723-
$this->isBindingRequired = $isUsingThisObject;
724-
$this->isScopeRequired = $isUsingScope;
725-
726698
$attributesCode = array_map(function ($attribute) {
727699
$arguments = $attribute->getArguments();
728700

@@ -740,107 +712,35 @@ public function getCode()
740712
return "#[$name($arguments)]";
741713
}, $this->getAttributes());
742714

743-
$lastItem = array_pop($candidates);
744-
745-
foreach ($candidates as $candidate) {
746-
$code = $candidate['code'];
747-
$use = $candidate['use'];
748-
$isShortClosure = $candidate['isShortClosure'];
749-
$isUsingThisObject = $candidate['isUsingThisObject'];
750-
$isUsingScope = $candidate['isUsingScope'];
715+
if (count($candidates) > 1) {
716+
$lastItem = array_pop($candidates);
751717

752-
// Verify Static
753-
$isStaticCode = mb_stripos($code, 'static') !== false;
754-
if (parent::isStatic() !== $isStaticCode) {
755-
continue;
756-
}
757-
758-
// Verify Parameters and Used Variables via parsing
759-
$tokens = token_get_all('<?php '.$code);
760-
$params = [];
761-
$vars = [];
762-
$state = 'start';
763-
foreach ($tokens as $token) {
764-
if (! is_array($token)) {
765-
if ($token === '(' && $state === 'start') {
766-
$state = 'params';
767-
} elseif ($token === ')' && $state === 'params') {
768-
$state = 'body';
769-
}
718+
foreach ($candidates as $candidate) {
719+
if (! $this->verifyCandidateSignature($candidate)) {
770720
continue;
771721
}
772-
if ($token[0] === T_VARIABLE) {
773-
$name = substr($token[1], 1);
774-
if ($state === 'params') {
775-
$params[] = $name;
776-
} elseif ($state === 'body') {
777-
if ($name !== 'this') {
778-
$vars[$name] = true;
779-
}
780-
}
781-
}
782-
}
783-
784-
// Verify Param Count
785-
if (parent::getNumberOfParameters() !== count($params)) {
786-
continue;
787-
}
788722

789-
// Verify Use Vars (for Short Closures especially)
790-
if ($isShortClosure) {
791-
$actualVars = array_keys(parent::getStaticVariables());
792-
$foundVars = array_keys($vars);
723+
$this->applyCandidate($candidate);
793724

794-
$foundCaptures = array_diff($foundVars, $params);
725+
$code = $candidate['code'];
795726

796-
if (count($foundCaptures) !== count($actualVars)) {
797-
continue;
727+
if (! empty($attributesCode)) {
728+
$code = implode("\n", array_merge($attributesCode, [$code]));
798729
}
799730

800-
if (count(array_diff($foundCaptures, $actualVars)) > 0) {
801-
continue;
802-
}
803-
} else {
804-
if (! empty($use)) {
805-
$actualStaticVariables = array_keys(parent::getStaticVariables());
806-
if (count(array_diff($use, $actualStaticVariables)) > 0) {
807-
continue;
808-
}
809-
}
810-
if (count($use) !== count(parent::getStaticVariables())) {
811-
continue;
812-
}
813-
}
731+
$this->code = $code;
814732

815-
if ($isShortClosure) {
816-
$this->useVariables = $this->getStaticVariables();
817-
} else {
818-
$this->useVariables = empty($use) ? $use : array_intersect_key($this->getStaticVariables(), array_flip($use));
733+
return $this->code;
819734
}
820735

821-
$this->isShortClosure = $isShortClosure;
822-
$this->isBindingRequired = $isUsingThisObject;
823-
$this->isScopeRequired = $isUsingScope;
824-
$this->code = $code;
825-
826-
return $this->code;
736+
$candidates[] = $lastItem;
827737
}
828738

829-
$code = $lastItem['code'];
830-
$use = $lastItem['use'];
831-
$isShortClosure = $lastItem['isShortClosure'];
832-
$isUsingThisObject = $lastItem['isUsingThisObject'];
833-
$isUsingScope = $lastItem['isUsingScope'];
739+
$lastItem = array_pop($candidates);
834740

835-
if ($isShortClosure) {
836-
$this->useVariables = $this->getStaticVariables();
837-
} else {
838-
$this->useVariables = empty($use) ? $use : array_intersect_key($this->getStaticVariables(), array_flip($use));
839-
}
741+
$this->applyCandidate($lastItem);
840742

841-
$this->isShortClosure = $isShortClosure;
842-
$this->isBindingRequired = $isUsingThisObject;
843-
$this->isScopeRequired = $isUsingScope;
743+
$code = $lastItem['code'];
844744

845745
if (! empty($attributesCode)) {
846746
$code = implode("\n", array_merge($attributesCode, [$code]));
@@ -1389,4 +1289,135 @@ protected function parseNameQualified($token)
13891289

13901290
return [$id_start, $id_start_ci, $id_name];
13911291
}
1292+
1293+
/**
1294+
* Collect a closure candidate and reset state for finding the next one.
1295+
*
1296+
* @param array $candidates
1297+
* @param string $code
1298+
* @param array $use
1299+
* @param bool $isShortClosure
1300+
* @param bool $isUsingThisObject
1301+
* @param bool $isUsingScope
1302+
* @return array
1303+
*/
1304+
protected function collectCandidate(&$candidates, $code, $use, $isShortClosure, $isUsingThisObject, $isUsingScope)
1305+
{
1306+
$candidates[] = [
1307+
'code' => $code,
1308+
'use' => $use,
1309+
'isShortClosure' => $isShortClosure,
1310+
'isUsingThisObject' => $isUsingThisObject,
1311+
'isUsingScope' => $isUsingScope,
1312+
];
1313+
1314+
return [
1315+
'code' => '',
1316+
'state' => 'start',
1317+
'open' => 0,
1318+
'use' => [],
1319+
'isShortClosure' => false,
1320+
'isUsingThisObject' => false,
1321+
'isUsingScope' => false,
1322+
];
1323+
}
1324+
1325+
/**
1326+
* Apply a candidate's properties to this instance.
1327+
*
1328+
* @param array $candidate
1329+
* @return void
1330+
*/
1331+
protected function applyCandidate($candidate)
1332+
{
1333+
if ($candidate['isShortClosure']) {
1334+
$this->useVariables = $this->getStaticVariables();
1335+
} else {
1336+
$this->useVariables = empty($candidate['use'])
1337+
? $candidate['use']
1338+
: array_intersect_key($this->getStaticVariables(), array_flip($candidate['use']));
1339+
}
1340+
1341+
$this->isShortClosure = $candidate['isShortClosure'];
1342+
$this->isBindingRequired = $candidate['isUsingThisObject'];
1343+
$this->isScopeRequired = $candidate['isUsingScope'];
1344+
}
1345+
1346+
/**
1347+
* Verify that a candidate matches the closure's signature.
1348+
*
1349+
* @param array $candidate
1350+
* @return bool
1351+
*/
1352+
protected function verifyCandidateSignature($candidate)
1353+
{
1354+
$code = $candidate['code'];
1355+
$use = $candidate['use'];
1356+
$isShortClosure = $candidate['isShortClosure'];
1357+
1358+
// Check if code starts with 'static' (more precise than searching anywhere in code)
1359+
$isStaticCode = strtolower(substr(ltrim($code), 0, 6)) === 'static';
1360+
if (parent::isStatic() !== $isStaticCode) {
1361+
return false;
1362+
}
1363+
1364+
// Parse the candidate to extract parameters and variables
1365+
$tokens = token_get_all('<?php '.$code);
1366+
$params = [];
1367+
$vars = [];
1368+
$state = 'start';
1369+
1370+
foreach ($tokens as $token) {
1371+
if (! is_array($token)) {
1372+
if ($token === '(' && $state === 'start') {
1373+
$state = 'params';
1374+
} elseif ($token === ')' && $state === 'params') {
1375+
$state = 'body';
1376+
}
1377+
1378+
continue;
1379+
}
1380+
1381+
if ($token[0] === T_VARIABLE) {
1382+
$name = substr($token[1], 1);
1383+
1384+
if ($state === 'params') {
1385+
$params[] = $name;
1386+
} elseif ($state === 'body' && $name !== 'this') {
1387+
$vars[$name] = true;
1388+
}
1389+
}
1390+
}
1391+
1392+
// Verify parameter count
1393+
if (parent::getNumberOfParameters() !== count($params)) {
1394+
return false;
1395+
}
1396+
1397+
// Verify use/captured variables
1398+
if ($isShortClosure) {
1399+
$actualVars = array_keys(parent::getStaticVariables());
1400+
$foundCaptures = array_diff(array_keys($vars), $params);
1401+
1402+
if (count($foundCaptures) !== count($actualVars)) {
1403+
return false;
1404+
}
1405+
1406+
if (count(array_diff($foundCaptures, $actualVars)) > 0) {
1407+
return false;
1408+
}
1409+
} else {
1410+
$actualStaticVariables = array_keys(parent::getStaticVariables());
1411+
1412+
if (! empty($use) && count(array_diff($use, $actualStaticVariables)) > 0) {
1413+
return false;
1414+
}
1415+
1416+
if (count($use) !== count(parent::getStaticVariables())) {
1417+
return false;
1418+
}
1419+
}
1420+
1421+
return true;
1422+
}
13921423
}

0 commit comments

Comments
 (0)