Skip to content

Commit 9b0b3df

Browse files
committed
Store string instead of array for Name
Name::$parts array is replaced by Name::$name string.
1 parent 7672b97 commit 9b0b3df

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+336
-727
lines changed

grammar/php5.y

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,13 @@ identifier:
4040
| semi_reserved { $$ = $1; }
4141
;
4242

43-
namespace_name_parts:
44-
T_STRING { init($1); }
45-
| namespace_name_parts T_NS_SEPARATOR T_STRING { push($1, $3); }
43+
raw_namespace_name:
44+
T_STRING { $$ = $1; }
45+
| raw_namespace_name T_NS_SEPARATOR T_STRING { $$ = $1 . '\\' . $3; }
4646
;
4747

4848
namespace_name:
49-
namespace_name_parts { $$ = Name[$1]; }
49+
raw_namespace_name { $$ = Name[$1]; }
5050
;
5151

5252
top_statement:
@@ -72,15 +72,15 @@ use_type:
7272
| T_CONST { $$ = Stmt\Use_::TYPE_CONSTANT; }
7373
;
7474

75-
/* Using namespace_name_parts here to avoid s/r conflict on T_NS_SEPARATOR */
75+
/* Using raw_namespace_name here to avoid s/r conflict on T_NS_SEPARATOR */
7676
group_use_declaration:
77-
T_USE use_type namespace_name_parts T_NS_SEPARATOR '{' unprefixed_use_declarations '}'
77+
T_USE use_type raw_namespace_name T_NS_SEPARATOR '{' unprefixed_use_declarations '}'
7878
{ $$ = Stmt\GroupUse[new Name($3, stackAttributes(#3)), $6, $2]; }
79-
| T_USE use_type T_NS_SEPARATOR namespace_name_parts T_NS_SEPARATOR '{' unprefixed_use_declarations '}'
79+
| T_USE use_type T_NS_SEPARATOR raw_namespace_name T_NS_SEPARATOR '{' unprefixed_use_declarations '}'
8080
{ $$ = Stmt\GroupUse[new Name($4, stackAttributes(#4)), $7, $2]; }
81-
| T_USE namespace_name_parts T_NS_SEPARATOR '{' inline_use_declarations '}'
81+
| T_USE raw_namespace_name T_NS_SEPARATOR '{' inline_use_declarations '}'
8282
{ $$ = Stmt\GroupUse[new Name($2, stackAttributes(#2)), $5, Stmt\Use_::TYPE_UNKNOWN]; }
83-
| T_USE T_NS_SEPARATOR namespace_name_parts T_NS_SEPARATOR '{' inline_use_declarations '}'
83+
| T_USE T_NS_SEPARATOR raw_namespace_name T_NS_SEPARATOR '{' inline_use_declarations '}'
8484
{ $$ = Stmt\GroupUse[new Name($3, stackAttributes(#3)), $6, Stmt\Use_::TYPE_UNKNOWN]; }
8585
;
8686

@@ -705,9 +705,9 @@ class_name:
705705
;
706706

707707
name:
708-
namespace_name_parts { $$ = Name[$1]; }
709-
| T_NS_SEPARATOR namespace_name_parts { $$ = Name\FullyQualified[$2]; }
710-
| T_NAMESPACE T_NS_SEPARATOR namespace_name_parts { $$ = Name\Relative[$3]; }
708+
raw_namespace_name { $$ = Name[$1]; }
709+
| T_NS_SEPARATOR raw_namespace_name { $$ = Name\FullyQualified[$2]; }
710+
| T_NAMESPACE T_NS_SEPARATOR raw_namespace_name { $$ = Name\Relative[$3]; }
711711
;
712712

713713
class_name_reference:

grammar/php7.y

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -40,13 +40,13 @@ identifier:
4040
| semi_reserved { $$ = $1; }
4141
;
4242

43-
namespace_name_parts:
44-
T_STRING { init($1); }
45-
| namespace_name_parts T_NS_SEPARATOR T_STRING { push($1, $3); }
43+
raw_namespace_name:
44+
T_STRING { $$ = $1; }
45+
| raw_namespace_name T_NS_SEPARATOR T_STRING { $$ = $1 . '\\' . $3; }
4646
;
4747

4848
namespace_name:
49-
namespace_name_parts { $$ = Name[$1]; }
49+
raw_namespace_name { $$ = Name[$1]; }
5050
;
5151

5252
top_statement:
@@ -72,15 +72,15 @@ use_type:
7272
| T_CONST { $$ = Stmt\Use_::TYPE_CONSTANT; }
7373
;
7474

75-
/* Using namespace_name_parts here to avoid s/r conflict on T_NS_SEPARATOR */
75+
/* Using raw_namespace_name here to avoid s/r conflict on T_NS_SEPARATOR */
7676
group_use_declaration:
77-
T_USE use_type namespace_name_parts T_NS_SEPARATOR '{' unprefixed_use_declarations '}'
77+
T_USE use_type raw_namespace_name T_NS_SEPARATOR '{' unprefixed_use_declarations '}'
7878
{ $$ = Stmt\GroupUse[new Name($3, stackAttributes(#3)), $6, $2]; }
79-
| T_USE use_type T_NS_SEPARATOR namespace_name_parts T_NS_SEPARATOR '{' unprefixed_use_declarations '}'
79+
| T_USE use_type T_NS_SEPARATOR raw_namespace_name T_NS_SEPARATOR '{' unprefixed_use_declarations '}'
8080
{ $$ = Stmt\GroupUse[new Name($4, stackAttributes(#4)), $7, $2]; }
81-
| T_USE namespace_name_parts T_NS_SEPARATOR '{' inline_use_declarations '}'
81+
| T_USE raw_namespace_name T_NS_SEPARATOR '{' inline_use_declarations '}'
8282
{ $$ = Stmt\GroupUse[new Name($2, stackAttributes(#2)), $5, Stmt\Use_::TYPE_UNKNOWN]; }
83-
| T_USE T_NS_SEPARATOR namespace_name_parts T_NS_SEPARATOR '{' inline_use_declarations '}'
83+
| T_USE T_NS_SEPARATOR raw_namespace_name T_NS_SEPARATOR '{' inline_use_declarations '}'
8484
{ $$ = Stmt\GroupUse[new Name($3, stackAttributes(#3)), $6, Stmt\Use_::TYPE_UNKNOWN]; }
8585
;
8686

@@ -659,9 +659,9 @@ class_name:
659659
;
660660

661661
name:
662-
namespace_name_parts { $$ = Name[$1]; }
663-
| T_NS_SEPARATOR namespace_name_parts { $$ = Name\FullyQualified[$2]; }
664-
| T_NAMESPACE T_NS_SEPARATOR namespace_name_parts { $$ = Name\Relative[$3]; }
662+
raw_namespace_name { $$ = Name[$1]; }
663+
| T_NS_SEPARATOR raw_namespace_name { $$ = Name\FullyQualified[$2]; }
664+
| T_NAMESPACE T_NS_SEPARATOR raw_namespace_name { $$ = Name\Relative[$3]; }
665665
;
666666

667667
class_name_reference:

lib/PhpParser/Node/Name.php

Lines changed: 59 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -6,26 +6,22 @@
66

77
class Name extends NodeAbstract
88
{
9-
/** @var string[] Parts of the name */
10-
public $parts;
9+
/** @var string Name */
10+
public $name;
1111

1212
/**
1313
* Constructs a name node.
1414
*
15-
* @param string|array $parts Parts of the name (or name as string)
15+
* @param string|array $name Name or parts of name
1616
* @param array $attributes Additional attributes
1717
*/
18-
public function __construct($parts, array $attributes = array()) {
19-
if (!is_array($parts)) {
20-
$parts = explode('\\', $parts);
21-
}
22-
18+
public function __construct($name, array $attributes = array()) {
2319
parent::__construct($attributes);
24-
$this->parts = $parts;
20+
$this->name = self::prepareName($name);
2521
}
2622

2723
public function getSubNodeNames() {
28-
return array('parts');
24+
return array('name');
2925
}
3026

3127
/**
@@ -34,7 +30,10 @@ public function getSubNodeNames() {
3430
* @return string First part of the name
3531
*/
3632
public function getFirst() {
37-
return $this->parts[0];
33+
if (false !== $first = strpos($this->name, '\\')) {
34+
return substr($this->name, 0, $first);
35+
}
36+
return $this->name;
3837
}
3938

4039
/**
@@ -43,7 +42,10 @@ public function getFirst() {
4342
* @return string Last part of the name
4443
*/
4544
public function getLast() {
46-
return $this->parts[count($this->parts) - 1];
45+
if (false !== $last = strrpos($this->name, '\\')) {
46+
return substr($this->name, $last + 1);
47+
}
48+
return $this->name;
4749
}
4850

4951
/**
@@ -52,7 +54,7 @@ public function getLast() {
5254
* @return bool Whether the name is unqualified
5355
*/
5456
public function isUnqualified() {
55-
return 1 == count($this->parts);
57+
return false === strpos($this->name, '\\');
5658
}
5759

5860
/**
@@ -61,7 +63,7 @@ public function isUnqualified() {
6163
* @return bool Whether the name is qualified
6264
*/
6365
public function isQualified() {
64-
return 1 < count($this->parts);
66+
return false !== strpos($this->name, '\\');
6567
}
6668

6769
/**
@@ -89,7 +91,7 @@ public function isRelative() {
8991
* @return string String representation
9092
*/
9193
public function toString() {
92-
return implode('\\', $this->parts);
94+
return $this->name;
9395
}
9496

9597
/**
@@ -99,7 +101,7 @@ public function toString() {
99101
* @return string String representation
100102
*/
101103
public function __toString() {
102-
return implode('\\', $this->parts);
104+
return $this->name;
103105
}
104106

105107
/**
@@ -108,18 +110,27 @@ public function __toString() {
108110
* This method returns a new instance of the same type as the original and with the same
109111
* attributes.
110112
*
111-
* If the slice is empty, a Name with an empty parts array is returned. While this is
112-
* meaningless in itself, it works correctly in conjunction with concat().
113+
* If the slice is empty, null is returned. The null value is handled correctly in conjunction
114+
* with concat().
113115
*
114116
* Offset and length have the same meaning as in array_slice().
115117
*
116118
* @param int $offset Offset to start the slice at (may be negative)
117119
* @param int|null $length Length of the slice (may be negative)
118120
*
119-
* @return static Sliced name
121+
* @return static|null Sliced name, or null for empty slices
120122
*/
121123
public function slice($offset, $length = null) {
122-
$numParts = count($this->parts);
124+
if ($offset === 1 && $length === null) {
125+
// Short-circuit the common case
126+
if (false !== $first = strpos($this->name, '\\')) {
127+
return new static(substr($this->name, $first + 1));
128+
}
129+
return null;
130+
}
131+
132+
$parts = explode('\\', $this->name);
133+
$numParts = count($parts);
123134

124135
$realOffset = $offset < 0 ? $offset + $numParts : $offset;
125136
if ($realOffset < 0 || $realOffset > $numParts) {
@@ -135,7 +146,11 @@ public function slice($offset, $length = null) {
135146
}
136147
}
137148

138-
return new static(array_slice($this->parts, $realOffset, $realLength), $this->attributes);
149+
$slice = array_slice($parts, $realOffset, $realLength);
150+
if (empty($slice)) {
151+
return null;
152+
}
153+
return new static(implode('\\', $slice), $this->attributes);
139154
}
140155

141156
/**
@@ -144,37 +159,49 @@ public function slice($offset, $length = null) {
144159
* The type of the generated instance depends on which class this method is called on, for
145160
* example Name\FullyQualified::concat() will yield a Name\FullyQualified instance.
146161
*
147-
* @param string|array|self $name1 The first name
148-
* @param string|array|self $name2 The second name
149-
* @param array $attributes Attributes to assign to concatenated name
162+
* Concatenation with null returns a new instance of the other name (or null if both are null).
163+
*
164+
* @param string|array|self|null $name1 The first name
165+
* @param string|array|self|null $name2 The second name
166+
* @param array $attributes Attributes to assign to concatenated name
150167
*
151168
* @return static Concatenated name
152169
*/
153170
public static function concat($name1, $name2, array $attributes = []) {
171+
if (null === $name1 && null === $name2) {
172+
return null;
173+
} else if (null === $name1) {
174+
return new static(self::prepareName($name2), $attributes);
175+
} else if (null === $name2) {
176+
return new static(self::prepareName($name1), $attributes);
177+
}
154178
return new static(
155-
array_merge(self::prepareName($name1), self::prepareName($name2)), $attributes
179+
self::prepareName($name1) . '\\' . self::prepareName($name2), $attributes
156180
);
157181
}
158182

159183
/**
160184
* Prepares a (string, array or Name node) name for use in name changing methods by converting
161-
* it to an array.
185+
* it into a string.
162186
*
163187
* @param string|array|self $name Name to prepare
164188
*
165-
* @return array Prepared name
189+
* @return string Prepared name
166190
*/
167191
private static function prepareName($name) {
168-
if (is_string($name)) {
169-
return explode('\\', $name);
170-
} elseif (is_array($name)) {
192+
if (\is_string($name)) {
171193
return $name;
172194
} elseif ($name instanceof self) {
173-
return $name->parts;
195+
return $name->name;
196+
} elseif (\is_array($name)) {
197+
if (empty($name)) {
198+
throw new \InvalidArgumentException('Name part array cannot be empty');
199+
}
200+
return implode('\\', $name);
174201
}
175202

176203
throw new \InvalidArgumentException(
177-
'When changing a name you need to pass either a string, an array or a Name node'
204+
'Expected string or Name node (or array -- deprecated)'
178205
);
179206
}
180207
}

lib/PhpParser/NodeVisitor/NameResolver.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -200,7 +200,7 @@ protected function resolveClassName(Name $name) {
200200
return FullyQualified::concat($this->namespace, $name, $name->getAttributes());
201201
}
202202

203-
return new FullyQualified($name->parts, $name->getAttributes());
203+
return new FullyQualified($name, $name->getAttributes());
204204
}
205205

206206
protected function resolveOtherName(Name $name, $type) {
@@ -229,7 +229,7 @@ protected function resolveOtherName(Name $name, $type) {
229229

230230
if (null === $this->namespace) {
231231
// outside of a namespace unaliased unqualified is same as fully qualified
232-
return new FullyQualified($name->parts, $name->getAttributes());
232+
return new FullyQualified($name, $name->getAttributes());
233233
}
234234

235235
// unqualified names inside a namespace cannot be resolved at compile-time
@@ -244,7 +244,7 @@ protected function resolveOtherName(Name $name, $type) {
244244
return FullyQualified::concat($this->namespace, $name, $name->getAttributes());
245245
}
246246

247-
return new FullyQualified($name->parts, $name->getAttributes());
247+
return new FullyQualified($name, $name->getAttributes());
248248
}
249249

250250
protected function addNamespacedName(Node $node) {

lib/PhpParser/Parser/Php5.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1241,11 +1241,11 @@ protected function reduceRule81() {
12411241
}
12421242

12431243
protected function reduceRule82() {
1244-
$this->semValue = array($this->semStack[$this->stackPos-(1-1)]);
1244+
$this->semValue = $this->semStack[$this->stackPos-(1-1)];
12451245
}
12461246

12471247
protected function reduceRule83() {
1248-
$this->semStack[$this->stackPos-(3-1)][] = $this->semStack[$this->stackPos-(3-3)]; $this->semValue = $this->semStack[$this->stackPos-(3-1)];
1248+
$this->semValue = $this->semStack[$this->stackPos-(3-1)] . '\\' . $this->semStack[$this->stackPos-(3-3)];
12491249
}
12501250

12511251
protected function reduceRule84() {

lib/PhpParser/Parser/Php7.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1124,11 +1124,11 @@ protected function reduceRule81() {
11241124
}
11251125

11261126
protected function reduceRule82() {
1127-
$this->semValue = array($this->semStack[$this->stackPos-(1-1)]);
1127+
$this->semValue = $this->semStack[$this->stackPos-(1-1)];
11281128
}
11291129

11301130
protected function reduceRule83() {
1131-
$this->semStack[$this->stackPos-(3-1)][] = $this->semStack[$this->stackPos-(3-3)]; $this->semValue = $this->semStack[$this->stackPos-(3-1)];
1131+
$this->semValue = $this->semStack[$this->stackPos-(3-1)] . '\\' . $this->semStack[$this->stackPos-(3-3)];
11321132
}
11331133

11341134
protected function reduceRule84() {

lib/PhpParser/PrettyPrinter/Standard.php

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,15 @@ protected function pNullableType(Node\NullableType $node) {
4040
// Names
4141

4242
protected function pName(Name $node) {
43-
return implode('\\', $node->parts);
43+
return $node->name;
4444
}
4545

4646
protected function pName_FullyQualified(Name\FullyQualified $node) {
47-
return '\\' . implode('\\', $node->parts);
47+
return '\\' . $node->name;
4848
}
4949

5050
protected function pName_Relative(Name\Relative $node) {
51-
return 'namespace\\' . implode('\\', $node->parts);
51+
return 'namespace\\' . $node->name;
5252
}
5353

5454
// Magic Constants

0 commit comments

Comments
 (0)