Represent empty Name::slice() using null

Instead of a Name([]) dummy value, that is invalid in other
contexts.
This commit is contained in:
Nikita Popov 2016-10-22 17:02:38 +02:00
parent 91cb82d3d2
commit fa7357b483
3 changed files with 40 additions and 33 deletions

View File

@ -104,15 +104,15 @@ class Name extends NodeAbstract
* This method returns a new instance of the same type as the original and with the same
* attributes.
*
* If the slice is empty, a Name with an empty parts array is returned. While this is
* meaningless in itself, it works correctly in conjunction with concat().
* If the slice is empty, null is returned. The null value will be correctly handled in
* concatenations using concat().
*
* Offset and length have the same meaning as in array_slice().
*
* @param int $offset Offset to start the slice at (may be negative)
* @param int|null $length Length of the slice (may be negative)
*
* @return static Sliced name
* @return static|null Sliced name
*/
public function slice($offset, $length = null) {
$numParts = count($this->parts);
@ -131,6 +131,11 @@ class Name extends NodeAbstract
}
}
if ($realLength === 0) {
// Empty slice is represented as null
return null;
}
return new static(array_slice($this->parts, $realOffset, $realLength), $this->attributes);
}
@ -140,16 +145,29 @@ class Name extends NodeAbstract
* The type of the generated instance depends on which class this method is called on, for
* example Name\FullyQualified::concat() will yield a Name\FullyQualified instance.
*
* @param string|array|self $name1 The first name
* @param string|array|self $name2 The second name
* @param array $attributes Attributes to assign to concatenated name
* If one of the arguments is null, a new instance of the other name will be returned. If both
* arguments are null, null will be returned. As such, writing
* Name::concat($namespace, $shortName)
* where $namespace is a Name node or null will work as expected.
*
* @return static Concatenated name
* @param string|array|self|null $name1 The first name
* @param string|array|self|null $name2 The second name
* @param array $attributes Attributes to assign to concatenated name
*
* @return static|null Concatenated name
*/
public static function concat($name1, $name2, array $attributes = []) {
return new static(
array_merge(self::prepareName($name1), self::prepareName($name2)), $attributes
);
if (null === $name1 && null === $name2) {
return null;
} elseif (null === $name1) {
return new static(self::prepareName($name2), $attributes);
} else if (null === $name2) {
return new static(self::prepareName($name1), $attributes);
} else {
return new static(
array_merge(self::prepareName($name1), self::prepareName($name2)), $attributes
);
}
}
/**

View File

@ -195,12 +195,8 @@ class NameResolver extends NodeVisitorAbstract
return FullyQualified::concat($alias, $name->slice(1), $name->getAttributes());
}
if (null !== $this->namespace) {
// if no alias exists prepend current namespace
return FullyQualified::concat($this->namespace, $name, $name->getAttributes());
}
return new FullyQualified($name, $name->getAttributes());
// if no alias exists prepend current namespace
return FullyQualified::concat($this->namespace, $name, $name->getAttributes());
}
protected function resolveOtherName(Name $name, $type) {
@ -239,19 +235,11 @@ class NameResolver extends NodeVisitorAbstract
return $name;
}
if (null !== $this->namespace) {
// if no alias exists prepend current namespace
return FullyQualified::concat($this->namespace, $name, $name->getAttributes());
}
return new FullyQualified($name, $name->getAttributes());
// if no alias exists prepend current namespace
return FullyQualified::concat($this->namespace, $name, $name->getAttributes());
}
protected function addNamespacedName(Node $node) {
if (null !== $this->namespace) {
$node->namespacedName = Name::concat($this->namespace, $node->name);
} else {
$node->namespacedName = new Name($node->name);
}
$node->namespacedName = Name::concat($this->namespace, $node->name);
}
}

View File

@ -36,16 +36,16 @@ class NameTest extends \PHPUnit_Framework_TestCase
$name = new Name('foo\bar\baz');
$this->assertEquals(new Name('foo\bar\baz'), $name->slice(0));
$this->assertEquals(new Name('bar\baz'), $name->slice(1));
$this->assertEquals(new Name([]), $name->slice(3));
$this->assertNull($name->slice(3));
$this->assertEquals(new Name('foo\bar\baz'), $name->slice(-3));
$this->assertEquals(new Name('bar\baz'), $name->slice(-2));
$this->assertEquals(new Name('foo\bar'), $name->slice(0, -1));
$this->assertEquals(new Name([]), $name->slice(0, -3));
$this->assertNull($name->slice(0, -3));
$this->assertEquals(new Name('bar'), $name->slice(1, -1));
$this->assertEquals(new Name([]), $name->slice(1, -2));
$this->assertNull($name->slice(1, -2));
$this->assertEquals(new Name('bar'), $name->slice(-2, 1));
$this->assertEquals(new Name('bar'), $name->slice(-2, -1));
$this->assertEquals(new Name([]), $name->slice(-2, -2));
$this->assertNull($name->slice(-2, -2));
}
/**
@ -93,8 +93,9 @@ class NameTest extends \PHPUnit_Framework_TestCase
Name\Relative::concat(new Name\FullyQualified('foo\bar'), 'baz', $attributes)
);
$this->assertEquals(new Name('foo'), Name::concat([], 'foo'));
$this->assertEquals(new Name([]), Name::concat([], []));
$this->assertEquals(new Name('foo'), Name::concat(null, 'foo'));
$this->assertEquals(new Name('foo'), Name::concat('foo', null));
$this->assertNull(Name::concat(null, null));
}
public function testIs() {