Skip to content

Commit 424a065

Browse files
Fix getAttributeNode and getAttributeNodeNS
1 parent d393a1d commit 424a065

File tree

4 files changed

+92
-2
lines changed

4 files changed

+92
-2
lines changed

resources/functionMap.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1572,8 +1572,8 @@
15721572
'DOMElement::get_attribute_node' => ['DomAttribute', 'name'=>'string'],
15731573
'DOMElement::get_elements_by_tagname' => ['array', 'name'=>'string'],
15741574
'DOMElement::getAttribute' => ['string', 'name'=>'string'],
1575-
'DOMElement::getAttributeNode' => ['DOMAttr', 'name'=>'string'],
1576-
'DOMElement::getAttributeNodeNS' => ['DOMAttr', 'namespaceuri'=>'string', 'localname'=>'string'],
1575+
'DOMElement::getAttributeNode' => ['__benevolent<DOMAttr|false>', 'name'=>'string'],
1576+
'DOMElement::getAttributeNodeNS' => ['__benevolent<DOMAttr|null>', 'namespaceuri'=>'string', 'localname'=>'string'],
15771577
'DOMElement::getAttributeNS' => ['string', 'namespaceuri'=>'string', 'localname'=>'string'],
15781578
'DOMElement::getElementsByTagName' => ['DOMNodeList', 'name'=>'string'],
15791579
'DOMElement::getElementsByTagNameNS' => ['DOMNodeList', 'namespaceuri'=>'string', 'localname'=>'string'],
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
declare(strict_types = 1);
4+
5+
namespace DOMLegacyNamedNodeMap;
6+
7+
use DOMAttr;
8+
use DOMElement;
9+
use DOMNode;
10+
use DOMNamedNodeMap;
11+
use function PHPStan\Testing\assertType;
12+
13+
class Foo
14+
{
15+
public function basic_node(DOMNode $node): void {
16+
if ($node->hasAttributes()) {
17+
assertType('DOMNamedNodeMap<DOMAttr>', $node->attributes);
18+
} else {
19+
// Can be either null or an empty DOMNamedNodeMap
20+
assertType('DOMNamedNodeMap<DOMAttr>|null', $node->attributes);
21+
}
22+
}
23+
24+
public function element_node(DOMElement $element): void
25+
{
26+
assertType('DOMNamedNodeMap<DOMAttr>', $element->attributes);
27+
if ($element->hasAttribute('class')) {
28+
$attribute = $element->getAttributeNode('class');
29+
assertType('(DOMAttr|false)', $attribute); // Could be DOMAttr
30+
assertType('string', $attribute->value);
31+
} else {
32+
$attribute = $element->getAttributeNode('class');
33+
assertType('(DOMAttr|false)', $attribute); // Could be false
34+
}
35+
}
36+
37+
public function element_node_attribute_fetch_via_attributes_property(DOMElement $element): void
38+
{
39+
assertType('DOMNamedNodeMap<DOMAttr>', $element->attributes);
40+
if ($element->hasAttribute('class')) {
41+
$attribute = $element->attributes->getNamedItem('class');
42+
if ($attribute === null) {
43+
return;
44+
}
45+
assertType(DOMAttr::class, $attribute);
46+
assertType('string', $attribute->value);
47+
}
48+
}
49+
}

tests/PHPStan/Rules/Properties/AccessPropertiesRuleTest.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1216,6 +1216,14 @@ public function testPrivatePropertyWithAllowedPropertyTagIsPublic(): void
12161216
$this->analyse([__DIR__ . '/data/private-property-with-allowed-property-tag-is-public.php'], []);
12171217
}
12181218

1219+
public function testDomExtensionLegacyTemplateNodes(): void
1220+
{
1221+
$this->checkThisOnly = false;
1222+
$this->checkUnionTypes = true;
1223+
$this->checkDynamicProperties = true;
1224+
$this->analyse([__DIR__ . '/data/dom-legacy-ext-template-nodes.php'], []);
1225+
}
1226+
12191227
public function testBug13537(): void
12201228
{
12211229
$this->checkThisOnly = false;
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
<?php
2+
3+
namespace DOMNodeStubsAccessProperties;
4+
5+
function basic_node(\DOMNode $node): void {
6+
var_dump($node->attributes);
7+
}
8+
9+
function element_node(\DOMElement $element): void
10+
{
11+
if ($element->hasAttribute('class')) {
12+
$attribute = $element->getAttributeNode('class');
13+
echo $attribute->value;
14+
}
15+
}
16+
17+
function element_node_attribute_fetch_via_attributes_property(\DOMElement $element): void
18+
{
19+
$attribute = $element->attributes->getNamedItem('class');
20+
if ($attribute === null) {
21+
return;
22+
}
23+
echo $attribute->value;
24+
}
25+
26+
function element_node_attribute_fetch_via_getAttributeNode(\DOMElement $element): void
27+
{
28+
$attribute = $element->getAttributeNode('class');
29+
if ($attribute === null) {
30+
return;
31+
}
32+
echo $attribute->value;
33+
}

0 commit comments

Comments
 (0)