1: <?php declare(strict_types=1);
2:
3: namespace PhpParser\Node\Expr;
4:
5: use PhpParser\Node\Arg;
6: use PhpParser\Node\ArgPlaceholder;
7: use PhpParser\Node\Expr;
8: use PhpParser\Node\VariadicPlaceholder;
9:
10: abstract class CallLike extends Expr {
11: /**
12: * Return raw arguments, which may be actual Args, VariadicPlaceholders for first-class
13: * callables, or ArgPlaceholders for partial function application.
14: *
15: * @return array<Arg|VariadicPlaceholder|ArgPlaceholder>
16: */
17: abstract public function getRawArgs(): array;
18:
19: /**
20: * Returns whether this call expression is actually a first class callable.
21: */
22: public function isFirstClassCallable(): bool {
23: $rawArgs = $this->getRawArgs();
24: return count($rawArgs) === 1 && current($rawArgs) instanceof VariadicPlaceholder;
25: }
26:
27: /**
28: * Returns whether this call expression is a partial function application, i.e. whether its
29: * argument list contains one or more "?" placeholders or a "..." placeholder. First-class
30: * callables are a special case of partial function application, so this also returns true
31: * for them.
32: */
33: public function isPartialFunctionApplication(): bool {
34: foreach ($this->getRawArgs() as $arg) {
35: if ($arg instanceof VariadicPlaceholder || $arg instanceof ArgPlaceholder) {
36: return true;
37: }
38: }
39: return false;
40: }
41:
42: /**
43: * Assert that this is not a partial function application (which includes first-class
44: * callables) and return only ordinary Args.
45: *
46: * @return Arg[]
47: */
48: public function getArgs(): array {
49: assert(!$this->isPartialFunctionApplication());
50: return $this->getRawArgs();
51: }
52:
53: /**
54: * Retrieves a specific argument from the raw arguments.
55: *
56: * Returns the named argument that matches the given `$name`, or the
57: * positional (unnamed) argument that exists at the given `$position`.
58: * Returns `null` if no match is found, or when a "..." placeholder is
59: * encountered, as argument positions are no longer known past that point.
60: * A "?" placeholder occupies its argument position, but is never returned,
61: * as it is not an actual argument.
62: */
63: public function getArg(string $name, int $position): ?Arg {
64: foreach ($this->getRawArgs() as $i => $arg) {
65: if ($arg instanceof VariadicPlaceholder) {
66: return null;
67: }
68: if ($arg instanceof ArgPlaceholder || $arg->unpack) {
69: continue;
70: }
71: if (
72: ($arg->name !== null && $arg->name->toString() === $name)
73: || ($arg->name === null && $i === $position)
74: ) {
75: return $arg;
76: }
77: }
78: return null;
79: }
80: }
81: