mirror of
https://github.com/phabelio/PHP-Parser.git
synced 2024-11-30 04:29:15 +01:00
Add CallLike parent class
This provides a helper to determine whether a call is a first-class callable, and a way to strip the args type to Arg[] if it isn't.
This commit is contained in:
parent
08501991d4
commit
a45fb2a621
@ -7,7 +7,10 @@ Version 4.12.1-dev
|
||||
* [PHP 8.1] Added support for explicit octal literals.
|
||||
* [PHP 8.1] Added support for first-class callables. These are represented using a call whose first
|
||||
argument is a `VariadicPlaceholder`. The representation is intended to be forward-compatible with
|
||||
partial function application, just like the PHP feature itself.
|
||||
partial function application, just like the PHP feature itself. Call nodes now extend from
|
||||
`Expr\CallLike`, which provides an `isFirstClassCallable()` method to determine whether a
|
||||
placeholder id present. `getArgs()` can be used to assert that the call is not a first-class
|
||||
callable and returns `Arg[]` rather than `array<Arg|VariadicPlaceholder>`.
|
||||
|
||||
Version 4.12.0 (2021-07-21)
|
||||
---------------------------
|
||||
|
39
lib/PhpParser/Node/Expr/CallLike.php
Normal file
39
lib/PhpParser/Node/Expr/CallLike.php
Normal file
@ -0,0 +1,39 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\VariadicPlaceholder;
|
||||
|
||||
abstract class CallLike extends Expr {
|
||||
/**
|
||||
* Return raw arguments, which may be actual Args, or VariadicPlaceholders for first-class
|
||||
* callables.
|
||||
*
|
||||
* @return array<Arg|VariadicPlaceholder>
|
||||
*/
|
||||
abstract public function getRawArgs(): array;
|
||||
|
||||
/**
|
||||
* Returns whether this call expression is actually a first class callable.
|
||||
*/
|
||||
public function isFirstClassCallable(): bool {
|
||||
foreach ($this->getRawArgs() as $arg) {
|
||||
if ($arg instanceof VariadicPlaceholder) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Assert that this is not a first-class callable and return only ordinary Args.
|
||||
*
|
||||
* @return Arg[]
|
||||
*/
|
||||
public function getArgs(): array {
|
||||
assert(!$this->isFirstClassCallable());
|
||||
return $this->getRawArgs();
|
||||
}
|
||||
}
|
@ -5,19 +5,19 @@ namespace PhpParser\Node\Expr;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
class FuncCall extends Expr
|
||||
class FuncCall extends CallLike
|
||||
{
|
||||
/** @var Node\Name|Expr Function name */
|
||||
public $name;
|
||||
/** @var Node\Arg[] Arguments */
|
||||
/** @var array<Node\Arg|Node\VariadicPlaceholder> Arguments */
|
||||
public $args;
|
||||
|
||||
/**
|
||||
* Constructs a function call node.
|
||||
*
|
||||
* @param Node\Name|Expr $name Function name
|
||||
* @param Node\Arg[] $args Arguments
|
||||
* @param array $attributes Additional attributes
|
||||
* @param Node\Name|Expr $name Function name
|
||||
* @param array<Node\Arg|Node\VariadicPlaceholder> $args Arguments
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct($name, array $args = [], array $attributes = []) {
|
||||
$this->attributes = $attributes;
|
||||
@ -32,4 +32,8 @@ class FuncCall extends Expr
|
||||
public function getType() : string {
|
||||
return 'Expr_FuncCall';
|
||||
}
|
||||
|
||||
public function getRawArgs(): array {
|
||||
return $this->args;
|
||||
}
|
||||
}
|
||||
|
@ -5,23 +5,24 @@ namespace PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\VariadicPlaceholder;
|
||||
|
||||
class MethodCall extends Expr
|
||||
class MethodCall extends CallLike
|
||||
{
|
||||
/** @var Expr Variable holding object */
|
||||
public $var;
|
||||
/** @var Identifier|Expr Method name */
|
||||
public $name;
|
||||
/** @var Arg[] Arguments */
|
||||
/** @var array<Arg|VariadicPlaceholder> Arguments */
|
||||
public $args;
|
||||
|
||||
/**
|
||||
* Constructs a function call node.
|
||||
*
|
||||
* @param Expr $var Variable holding object
|
||||
* @param string|Identifier|Expr $name Method name
|
||||
* @param Arg[] $args Arguments
|
||||
* @param array $attributes Additional attributes
|
||||
* @param Expr $var Variable holding object
|
||||
* @param string|Identifier|Expr $name Method name
|
||||
* @param array<Arg|VariadicPlaceholder> $args Arguments
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct(Expr $var, $name, array $args = [], array $attributes = []) {
|
||||
$this->attributes = $attributes;
|
||||
@ -37,4 +38,8 @@ class MethodCall extends Expr
|
||||
public function getType() : string {
|
||||
return 'Expr_MethodCall';
|
||||
}
|
||||
|
||||
public function getRawArgs(): array {
|
||||
return $this->args;
|
||||
}
|
||||
}
|
||||
|
@ -3,20 +3,22 @@
|
||||
namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\VariadicPlaceholder;
|
||||
|
||||
class New_ extends Expr
|
||||
class New_ extends CallLike
|
||||
{
|
||||
/** @var Node\Name|Expr|Node\Stmt\Class_ Class name */
|
||||
public $class;
|
||||
/** @var Node\Arg[] Arguments */
|
||||
/** @var array<Arg|VariadicPlaceholder> Arguments */
|
||||
public $args;
|
||||
|
||||
/**
|
||||
* Constructs a function call node.
|
||||
*
|
||||
* @param Node\Name|Expr|Node\Stmt\Class_ $class Class name (or class node for anonymous classes)
|
||||
* @param Node\Arg[] $args Arguments
|
||||
* @param array<Arg|VariadicPlaceholder> $args Arguments
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct($class, array $args = [], array $attributes = []) {
|
||||
@ -32,4 +34,8 @@ class New_ extends Expr
|
||||
public function getType() : string {
|
||||
return 'Expr_New';
|
||||
}
|
||||
|
||||
public function getRawArgs(): array {
|
||||
return $this->args;
|
||||
}
|
||||
}
|
||||
|
@ -3,25 +3,27 @@
|
||||
namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Expr;
|
||||
use PhpParser\Node\Identifier;
|
||||
use PhpParser\Node\VariadicPlaceholder;
|
||||
|
||||
class StaticCall extends Expr
|
||||
class StaticCall extends CallLike
|
||||
{
|
||||
/** @var Node\Name|Expr Class name */
|
||||
public $class;
|
||||
/** @var Identifier|Expr Method name */
|
||||
public $name;
|
||||
/** @var Node\Arg[] Arguments */
|
||||
/** @var array<Arg|VariadicPlaceholder> Arguments */
|
||||
public $args;
|
||||
|
||||
/**
|
||||
* Constructs a static method call node.
|
||||
*
|
||||
* @param Node\Name|Expr $class Class name
|
||||
* @param string|Identifier|Expr $name Method name
|
||||
* @param Node\Arg[] $args Arguments
|
||||
* @param array $attributes Additional attributes
|
||||
* @param Node\Name|Expr $class Class name
|
||||
* @param string|Identifier|Expr $name Method name
|
||||
* @param array<Arg|VariadicPlaceholder> $args Arguments
|
||||
* @param array $attributes Additional attributes
|
||||
*/
|
||||
public function __construct($class, $name, array $args = [], array $attributes = []) {
|
||||
$this->attributes = $attributes;
|
||||
@ -37,4 +39,8 @@ class StaticCall extends Expr
|
||||
public function getType() : string {
|
||||
return 'Expr_StaticCall';
|
||||
}
|
||||
|
||||
public function getRawArgs(): array {
|
||||
return $this->args;
|
||||
}
|
||||
}
|
||||
|
36
test/PhpParser/Node/Expr/CallableLikeTest.php
Normal file
36
test/PhpParser/Node/Expr/CallableLikeTest.php
Normal file
@ -0,0 +1,36 @@
|
||||
<?php declare(strict_types=1);
|
||||
|
||||
namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Arg;
|
||||
use PhpParser\Node\Name;
|
||||
use PhpParser\Node\Scalar\LNumber;
|
||||
use PhpParser\Node\VariadicPlaceholder;
|
||||
|
||||
class CallableLikeTest extends \PHPUnit\Framework\TestCase {
|
||||
/**
|
||||
* @dataProvider provideTestIsFirstClassCallable
|
||||
*/
|
||||
public function testIsFirstClassCallable(CallLike $node, bool $isFirstClassCallable) {
|
||||
$this->assertSame($isFirstClassCallable, $node->isFirstClassCallable());
|
||||
if (!$isFirstClassCallable) {
|
||||
$this->assertSame($node->getRawArgs(), $node->getArgs());
|
||||
}
|
||||
}
|
||||
|
||||
public function provideTestIsFirstClassCallable() {
|
||||
$normalArgs = [new Arg(new LNumber(1))];
|
||||
$callableArgs = [new VariadicPlaceholder()];
|
||||
return [
|
||||
[new FuncCall(new Name('test'), $normalArgs), false],
|
||||
[new FuncCall(new Name('test'), $callableArgs), true],
|
||||
[new MethodCall(new Variable('this'), 'test', $normalArgs), false],
|
||||
[new MethodCall(new Variable('this'), 'test', $callableArgs), true],
|
||||
[new StaticCall(new Name('Test'), 'test', $normalArgs), false],
|
||||
[new StaticCall(new Name('Test'), 'test', $callableArgs), true],
|
||||
[new New_(new Name('Test'), $normalArgs), false],
|
||||
// This is not legal code, but accepted by the parser.
|
||||
[new New_(new Name('Test'), $callableArgs), true],
|
||||
];
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user