Skip to content

Commit 470e9bb

Browse files
committed
Fix 13365
1 parent c0e6f0e commit 470e9bb

File tree

3 files changed

+50
-9
lines changed

3 files changed

+50
-9
lines changed

stubs/dom.stub

Lines changed: 31 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,12 @@ class DOMNode
3131
{
3232

3333
/**
34-
* @var DOMNamedNodeMap|null
34+
* @var DOMNamedNodeMap<DOMAttr>|null
3535
*/
3636
public $attributes;
3737

3838
/**
39-
* @phpstan-assert-if-true =DOMNamedNodeMap $this->attributes
39+
* @phpstan-assert-if-true =DOMNamedNodeMap<DOMAttr> $this->attributes
4040
* @return bool
4141
*/
4242
public function hasAttributes() {}
@@ -46,7 +46,7 @@ class DOMNode
4646
class DOMElement extends DOMNode
4747
{
4848

49-
/** @var DOMNamedNodeMap */
49+
/** @var DOMNamedNodeMap<DOMAttr> */
5050
public $attributes;
5151

5252
/** @var DOMDocument */
@@ -96,7 +96,7 @@ class DOMXPath
9696

9797
}
9898

99-
class DOMAttr
99+
class DOMAttr extends DOMNode
100100
{
101101

102102
/** @var DOMDocument */
@@ -155,11 +155,37 @@ class DOMProcessingInstruction
155155
}
156156

157157
/**
158+
* @template-covariant TNode as DOMNode
159+
* @implements Traversable<int, TNode>
160+
* @implements IteratorAggregate<int, TNode>
161+
*
158162
* @property-read int $length
159163
*/
160-
class DOMNamedNodeMap
164+
class DOMNamedNodeMap implements Traversable, IteratorAggregate, Countable
161165
{
166+
/**
167+
* @return Iterator<TNode>
168+
*/
169+
public function getIterator(): Iterator {}
170+
171+
/**
172+
* @param string $qualifiedName
173+
* @return ?TNode
174+
*/
175+
public function getNamedItem($qualifiedName): ?DOMNode {}
162176

177+
/**
178+
* @param ?string $namespace
179+
* @param string $localName
180+
* @return ?TNode
181+
*/
182+
public function getNamedItemNS($namespace, $localName): ?DOMNode {}
183+
184+
/**
185+
* @param int $index
186+
* @return ?TNode
187+
*/
188+
public function item($index): ?DOMNode {}
163189
}
164190

165191
class DOMText

tests/PHPStan/Analyser/nsrt/bug-13076.php

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,18 @@ class Foo
99
public function test(\DOMNode $node): void
1010
{
1111
if ($node->hasAttributes()) {
12-
assertType('DOMNamedNodeMap', $node->attributes);
12+
assertType('DOMNamedNodeMap<DOMAttr>', $node->attributes);
1313
} else {
14-
assertType('DOMNamedNodeMap|null', $node->attributes);
14+
assertType('DOMNamedNodeMap<DOMAttr>|null', $node->attributes);
1515
}
1616
}
1717

1818
public function testElement(\DOMElement $node): void
1919
{
2020
if ($node->hasAttributes()) {
21-
assertType('DOMNamedNodeMap', $node->attributes);
21+
assertType('DOMNamedNodeMap<DOMAttr>', $node->attributes);
2222
} else {
23-
assertType('DOMNamedNodeMap', $node->attributes);
23+
assertType('DOMNamedNodeMap<DOMAttr>', $node->attributes);
2424
}
2525
}
2626
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Bug13365;
4+
5+
use function PHPStan\Testing\assertType;
6+
7+
class Foo
8+
{
9+
public function test(\DOMElement $element): void
10+
{
11+
foreach ($element->attributes ?? [] as $attr) {
12+
assertType('DOMAttr', $attr);
13+
}
14+
}
15+
}

0 commit comments

Comments
 (0)