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;
|
||||
|
||||
/**
|
||||
* 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
|
||||
{
|
||||
/**
|
||||
@ -41,6 +55,15 @@ interface Node
|
||||
*/
|
||||
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.
|
||||
*
|
||||
@ -74,4 +97,37 @@ interface Node
|
||||
* @return array
|
||||
*/
|
||||
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;
|
||||
|
||||
/**
|
||||
* @property Name $namespacedName Namespace-prefixed name (requires NameResolver). This only applies
|
||||
* to freestanding (non-class) constants.
|
||||
*/
|
||||
class Const_ extends NodeAbstract
|
||||
{
|
||||
/** @var string Name */
|
||||
|
@ -4,6 +4,9 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property int $kind One of the KIND_* class constants
|
||||
*/
|
||||
class Array_ extends Expr
|
||||
{
|
||||
// For use in "kind" attribute
|
||||
|
@ -4,6 +4,9 @@ namespace PhpParser\Node\Expr;
|
||||
|
||||
use PhpParser\Node\Expr;
|
||||
|
||||
/**
|
||||
* @property int $kind One of the KIND_* class constants
|
||||
*/
|
||||
class Exit_ extends Expr
|
||||
{
|
||||
/* For use in "kind" attribute */
|
||||
|
@ -4,6 +4,10 @@ namespace 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
|
||||
{
|
||||
/** @var array Encaps list */
|
||||
|
@ -5,6 +5,9 @@ namespace PhpParser\Node\Scalar;
|
||||
use PhpParser\Error;
|
||||
use PhpParser\Node\Scalar;
|
||||
|
||||
/**
|
||||
* @property int $kind One of the KIND_* class constants
|
||||
*/
|
||||
class LNumber extends Scalar
|
||||
{
|
||||
/* For use in "kind" attribute */
|
||||
|
@ -5,6 +5,10 @@ namespace PhpParser\Node\Scalar;
|
||||
use PhpParser\Error;
|
||||
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
|
||||
{
|
||||
/* For use in "kind" attribute */
|
||||
|
@ -4,6 +4,9 @@ namespace PhpParser\Node\Stmt;
|
||||
|
||||
use PhpParser\Node;
|
||||
|
||||
/**
|
||||
* @property Node\Name $namespacedName Namespace-prefixed name (requires NameResolver)
|
||||
*/
|
||||
abstract class ClassLike extends Node\Stmt {
|
||||
/** @var string Name */
|
||||
public $name;
|
||||
|
@ -5,6 +5,9 @@ namespace PhpParser\Node\Stmt;
|
||||
use PhpParser\Node;
|
||||
use PhpParser\Node\FunctionLike;
|
||||
|
||||
/**
|
||||
* @property Node\Name $namespacedName Namespace-prefixed name (requires NameResolver)
|
||||
*/
|
||||
class Function_ extends Node\Stmt implements FunctionLike
|
||||
{
|
||||
/** @var bool Whether function returns by reference */
|
||||
|
@ -4,6 +4,9 @@ namespace 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
|
||||
{
|
||||
/** @var string String */
|
||||
|
@ -4,6 +4,7 @@ namespace PhpParser;
|
||||
|
||||
abstract class NodeAbstract implements Node, \JsonSerializable
|
||||
{
|
||||
/** @var array Node attributes */
|
||||
protected $attributes;
|
||||
|
||||
/**
|
||||
@ -108,4 +109,24 @@ abstract class NodeAbstract implements Node, \JsonSerializable
|
||||
public function jsonSerialize() {
|
||||
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
|
||||
// add the namespaced version of the name as an attribute
|
||||
$name->setAttribute('namespacedName',
|
||||
FullyQualified::concat($this->namespace, $name, $name->getAttributes()));
|
||||
$name->namespacedName =
|
||||
FullyQualified::concat($this->namespace, $name, $name->getAttributes());
|
||||
return $name;
|
||||
}
|
||||
|
||||
|
@ -34,7 +34,7 @@ class NodeAbstractTest extends \PHPUnit_Framework_TestCase
|
||||
);
|
||||
|
||||
$node = new DummyNode('value1', 'value2', $attributes);
|
||||
$node->notSubNode = 'value3';
|
||||
$attributes['notSubNode'] = $node->notSubNode = 'value3';
|
||||
|
||||
return array(
|
||||
array($attributes, $node),
|
||||
@ -119,7 +119,7 @@ class NodeAbstractTest extends \PHPUnit_Framework_TestCase
|
||||
*/
|
||||
public function testIteration(array $attributes, Node $node) {
|
||||
// Iteration is simple object iteration over properties,
|
||||
// not over subnodes
|
||||
// which coincide with the subnodes
|
||||
$i = 0;
|
||||
foreach ($node as $key => $value) {
|
||||
if ($i === 0) {
|
||||
@ -128,15 +128,12 @@ class NodeAbstractTest extends \PHPUnit_Framework_TestCase
|
||||
} else if ($i === 1) {
|
||||
$this->assertSame('subNode2', $key);
|
||||
$this->assertSame('value2', $value);
|
||||
} else if ($i === 2) {
|
||||
$this->assertSame('notSubNode', $key);
|
||||
$this->assertSame('value3', $value);
|
||||
} else {
|
||||
throw new \Exception;
|
||||
}
|
||||
$i++;
|
||||
}
|
||||
$this->assertSame(3, $i);
|
||||
$this->assertSame(2, $i);
|
||||
}
|
||||
|
||||
public function testAttributes() {
|
||||
@ -165,6 +162,28 @@ class NodeAbstractTest extends \PHPUnit_Framework_TestCase
|
||||
),
|
||||
$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() {
|
||||
|
Loading…
Reference in New Issue
Block a user