mirror of
https://github.com/danog/PHP-Parser.git
synced 2024-11-30 04:19:30 +01:00
Add Node property overloads for accessing attributes
Node attributes are now also accessible as ordinary properties. Accessing an undefined attribute throws -- the getAttribute() default value behavior can be replicated using coalescing. @property declarations for all the standard attributes have been added to the relevant nodes. Of course, whether they are actually available depends on configuration.
This commit is contained in:
parent
4e25f51581
commit
91f77968c2
@ -2,6 +2,20 @@
|
|||||||
|
|
||||||
namespace PhpParser;
|
namespace PhpParser;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* AST node.
|
||||||
|
*
|
||||||
|
* The following attributes are available depending on the 'usedAttributes' option passed to the
|
||||||
|
* lexer.
|
||||||
|
*
|
||||||
|
* @property Comment[] $comments Comments preceding this node
|
||||||
|
* @property int $startLine Line the node starts at (1-based)
|
||||||
|
* @property int $endLine Line the node end at (1-based)
|
||||||
|
* @property int $startFilePos File offset the node starts at (0-based)
|
||||||
|
* @property int $endFilePos File offset the node ends at (0-based)
|
||||||
|
* @property int $startTokenPos Token offset the node starts at (0-based)
|
||||||
|
* @property int $endTokenPos Token offset the node ends at (0-based)
|
||||||
|
*/
|
||||||
interface Node
|
interface Node
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
@ -41,6 +55,15 @@ interface Node
|
|||||||
*/
|
*/
|
||||||
public function getDocComment();
|
public function getDocComment();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the doc comment of the node.
|
||||||
|
*
|
||||||
|
* This will either replace an existing doc comment or add it to the comments array.
|
||||||
|
*
|
||||||
|
* @param Comment\Doc $docComment Doc comment to set
|
||||||
|
*/
|
||||||
|
public function setDocComment(Comment\Doc $docComment);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets an attribute on a node.
|
* Sets an attribute on a node.
|
||||||
*
|
*
|
||||||
@ -74,4 +97,37 @@ interface Node
|
|||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function getAttributes();
|
public function getAttributes();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of an attribute.
|
||||||
|
*
|
||||||
|
* @param string $key Name of the attribute
|
||||||
|
*
|
||||||
|
* @return mixed Value of the attribute
|
||||||
|
*/
|
||||||
|
public function &__get($key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the value of an attribute.
|
||||||
|
*
|
||||||
|
* @param string $key Name of the attribute
|
||||||
|
* @param mixed $value Value to set
|
||||||
|
*/
|
||||||
|
public function __set($key, $value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check whether an attribute exists and is non-null.
|
||||||
|
*
|
||||||
|
* @param string $key Name of the attribute
|
||||||
|
*
|
||||||
|
* @return bool Whether the attribute exists and is non-null
|
||||||
|
*/
|
||||||
|
public function __isset($key);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes an attribute.
|
||||||
|
*
|
||||||
|
* @param string $key Name of the attribute.
|
||||||
|
*/
|
||||||
|
public function __unset($key);
|
||||||
}
|
}
|
@ -4,6 +4,10 @@ namespace PhpParser\Node;
|
|||||||
|
|
||||||
use PhpParser\NodeAbstract;
|
use PhpParser\NodeAbstract;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property Name $namespacedName Namespace-prefixed name (requires NameResolver). This only applies
|
||||||
|
* to freestanding (non-class) constants.
|
||||||
|
*/
|
||||||
class Const_ extends NodeAbstract
|
class Const_ extends NodeAbstract
|
||||||
{
|
{
|
||||||
/** @var string Name */
|
/** @var string Name */
|
||||||
|
@ -4,6 +4,9 @@ namespace PhpParser\Node\Expr;
|
|||||||
|
|
||||||
use PhpParser\Node\Expr;
|
use PhpParser\Node\Expr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $kind One of the KIND_* class constants
|
||||||
|
*/
|
||||||
class Array_ extends Expr
|
class Array_ extends Expr
|
||||||
{
|
{
|
||||||
// For use in "kind" attribute
|
// For use in "kind" attribute
|
||||||
|
@ -4,6 +4,9 @@ namespace PhpParser\Node\Expr;
|
|||||||
|
|
||||||
use PhpParser\Node\Expr;
|
use PhpParser\Node\Expr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $kind One of the KIND_* class constants
|
||||||
|
*/
|
||||||
class Exit_ extends Expr
|
class Exit_ extends Expr
|
||||||
{
|
{
|
||||||
/* For use in "kind" attribute */
|
/* For use in "kind" attribute */
|
||||||
|
@ -4,6 +4,10 @@ namespace PhpParser\Node\Scalar;
|
|||||||
|
|
||||||
use PhpParser\Node\Scalar;
|
use PhpParser\Node\Scalar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $kind One of the String_::KIND_* class constants
|
||||||
|
* @property string $docLabel Label of doc comment (only available if string defined as doc string)
|
||||||
|
*/
|
||||||
class Encapsed extends Scalar
|
class Encapsed extends Scalar
|
||||||
{
|
{
|
||||||
/** @var array Encaps list */
|
/** @var array Encaps list */
|
||||||
|
@ -5,6 +5,9 @@ namespace PhpParser\Node\Scalar;
|
|||||||
use PhpParser\Error;
|
use PhpParser\Error;
|
||||||
use PhpParser\Node\Scalar;
|
use PhpParser\Node\Scalar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $kind One of the KIND_* class constants
|
||||||
|
*/
|
||||||
class LNumber extends Scalar
|
class LNumber extends Scalar
|
||||||
{
|
{
|
||||||
/* For use in "kind" attribute */
|
/* For use in "kind" attribute */
|
||||||
|
@ -5,6 +5,10 @@ namespace PhpParser\Node\Scalar;
|
|||||||
use PhpParser\Error;
|
use PhpParser\Error;
|
||||||
use PhpParser\Node\Scalar;
|
use PhpParser\Node\Scalar;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property int $kind One of the KIND_* class constants
|
||||||
|
* @property string $docLabel Label of doc comment (only available if string defined as doc string)
|
||||||
|
*/
|
||||||
class String_ extends Scalar
|
class String_ extends Scalar
|
||||||
{
|
{
|
||||||
/* For use in "kind" attribute */
|
/* For use in "kind" attribute */
|
||||||
|
@ -4,6 +4,9 @@ namespace PhpParser\Node\Stmt;
|
|||||||
|
|
||||||
use PhpParser\Node;
|
use PhpParser\Node;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property Node\Name $namespacedName Namespace-prefixed name (requires NameResolver)
|
||||||
|
*/
|
||||||
abstract class ClassLike extends Node\Stmt {
|
abstract class ClassLike extends Node\Stmt {
|
||||||
/** @var string Name */
|
/** @var string Name */
|
||||||
public $name;
|
public $name;
|
||||||
|
@ -5,6 +5,9 @@ namespace PhpParser\Node\Stmt;
|
|||||||
use PhpParser\Node;
|
use PhpParser\Node;
|
||||||
use PhpParser\Node\FunctionLike;
|
use PhpParser\Node\FunctionLike;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property Node\Name $namespacedName Namespace-prefixed name (requires NameResolver)
|
||||||
|
*/
|
||||||
class Function_ extends Node\Stmt implements FunctionLike
|
class Function_ extends Node\Stmt implements FunctionLike
|
||||||
{
|
{
|
||||||
/** @var bool Whether function returns by reference */
|
/** @var bool Whether function returns by reference */
|
||||||
|
@ -4,6 +4,9 @@ namespace PhpParser\Node\Stmt;
|
|||||||
|
|
||||||
use PhpParser\Node\Stmt;
|
use PhpParser\Node\Stmt;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @property bool $hasLeadingNewline Whether the inline has a leading newline that has been ignored
|
||||||
|
*/
|
||||||
class InlineHTML extends Stmt
|
class InlineHTML extends Stmt
|
||||||
{
|
{
|
||||||
/** @var string String */
|
/** @var string String */
|
||||||
|
@ -4,6 +4,7 @@ namespace PhpParser;
|
|||||||
|
|
||||||
abstract class NodeAbstract implements Node, \JsonSerializable
|
abstract class NodeAbstract implements Node, \JsonSerializable
|
||||||
{
|
{
|
||||||
|
/** @var array Node attributes */
|
||||||
protected $attributes;
|
protected $attributes;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -108,4 +109,24 @@ abstract class NodeAbstract implements Node, \JsonSerializable
|
|||||||
public function jsonSerialize() {
|
public function jsonSerialize() {
|
||||||
return ['nodeType' => $this->getType()] + get_object_vars($this);
|
return ['nodeType' => $this->getType()] + get_object_vars($this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public function &__get($key) {
|
||||||
|
if (!array_key_exists($key, $this->attributes)) {
|
||||||
|
throw new \LogicException("Attribute \"$key\" does not exist");
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->attributes[$key];
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __set($key, $value) {
|
||||||
|
$this->attributes[$key] = $value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __isset($key) {
|
||||||
|
return isset($this->attributes[$key]);
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __unset($key) {
|
||||||
|
unset($this->attributes[$key]);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -234,8 +234,8 @@ class NameResolver extends NodeVisitorAbstract
|
|||||||
|
|
||||||
// unqualified names inside a namespace cannot be resolved at compile-time
|
// unqualified names inside a namespace cannot be resolved at compile-time
|
||||||
// add the namespaced version of the name as an attribute
|
// add the namespaced version of the name as an attribute
|
||||||
$name->setAttribute('namespacedName',
|
$name->namespacedName =
|
||||||
FullyQualified::concat($this->namespace, $name, $name->getAttributes()));
|
FullyQualified::concat($this->namespace, $name, $name->getAttributes());
|
||||||
return $name;
|
return $name;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -254,4 +254,4 @@ class NameResolver extends NodeVisitorAbstract
|
|||||||
$node->namespacedName = new Name($node->name);
|
$node->namespacedName = new Name($node->name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -34,7 +34,7 @@ class NodeAbstractTest extends \PHPUnit_Framework_TestCase
|
|||||||
);
|
);
|
||||||
|
|
||||||
$node = new DummyNode('value1', 'value2', $attributes);
|
$node = new DummyNode('value1', 'value2', $attributes);
|
||||||
$node->notSubNode = 'value3';
|
$attributes['notSubNode'] = $node->notSubNode = 'value3';
|
||||||
|
|
||||||
return array(
|
return array(
|
||||||
array($attributes, $node),
|
array($attributes, $node),
|
||||||
@ -119,7 +119,7 @@ class NodeAbstractTest extends \PHPUnit_Framework_TestCase
|
|||||||
*/
|
*/
|
||||||
public function testIteration(array $attributes, Node $node) {
|
public function testIteration(array $attributes, Node $node) {
|
||||||
// Iteration is simple object iteration over properties,
|
// Iteration is simple object iteration over properties,
|
||||||
// not over subnodes
|
// which coincide with the subnodes
|
||||||
$i = 0;
|
$i = 0;
|
||||||
foreach ($node as $key => $value) {
|
foreach ($node as $key => $value) {
|
||||||
if ($i === 0) {
|
if ($i === 0) {
|
||||||
@ -128,15 +128,12 @@ class NodeAbstractTest extends \PHPUnit_Framework_TestCase
|
|||||||
} else if ($i === 1) {
|
} else if ($i === 1) {
|
||||||
$this->assertSame('subNode2', $key);
|
$this->assertSame('subNode2', $key);
|
||||||
$this->assertSame('value2', $value);
|
$this->assertSame('value2', $value);
|
||||||
} else if ($i === 2) {
|
|
||||||
$this->assertSame('notSubNode', $key);
|
|
||||||
$this->assertSame('value3', $value);
|
|
||||||
} else {
|
} else {
|
||||||
throw new \Exception;
|
throw new \Exception;
|
||||||
}
|
}
|
||||||
$i++;
|
$i++;
|
||||||
}
|
}
|
||||||
$this->assertSame(3, $i);
|
$this->assertSame(2, $i);
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testAttributes() {
|
public function testAttributes() {
|
||||||
@ -165,6 +162,28 @@ class NodeAbstractTest extends \PHPUnit_Framework_TestCase
|
|||||||
),
|
),
|
||||||
$node->getAttributes()
|
$node->getAttributes()
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// Test overloaded properties accessing attributes as well
|
||||||
|
$this->assertTrue(isset($node->key));
|
||||||
|
$this->assertSame('value', $node->key);
|
||||||
|
$node->key = 'newValue';
|
||||||
|
$this->assertSame('newValue', $node->key);
|
||||||
|
unset($node->key);
|
||||||
|
$this->assertFalse(isset($node->key));
|
||||||
|
|
||||||
|
$this->assertFalse(isset($node->null)); // False per standard semantics
|
||||||
|
$this->assertNull($node->null);
|
||||||
|
$this->assertSame(array('null' => null), $node->getAttributes());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @expectedException \LogicException
|
||||||
|
* @expectedExceptionMessage Attribute "foo" does not exist
|
||||||
|
*/
|
||||||
|
public function testUnknownAttribute() {
|
||||||
|
/** @var $node Node */
|
||||||
|
$node = $this->getMockForAbstractClass('PhpParser\NodeAbstract');
|
||||||
|
$node->foo;
|
||||||
}
|
}
|
||||||
|
|
||||||
public function testJsonSerialization() {
|
public function testJsonSerialization() {
|
||||||
|
Loading…
Reference in New Issue
Block a user