• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

voku / simple_html_dom / 24350711475

13 Apr 2026 03:04PM UTC coverage: 69.192% (+0.01%) from 69.18%
24350711475

Pull #131

github

web-flow
Merge 63bc59d71 into b2c38d5a9
Pull Request #131: Add `remove()` method to SimpleHtmlDom; fix `parentNode` null dereference

5 of 6 new or added lines in 2 files covered. (83.33%)

5 existing lines in 1 file now uncovered.

1370 of 1980 relevant lines covered (69.19%)

228.12 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

88.41
/src/voku/helper/AbstractSimpleHtmlDom.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace voku\helper;
6

7
abstract class AbstractSimpleHtmlDom
8
{
9
    /**
10
     * @var array
11
     */
12
    protected static $functionAliases = [
13
        'children'     => 'childNodes',
14
        'first_child'  => 'firstChild',
15
        'last_child'   => 'lastChild',
16
        'next_sibling' => 'nextSibling',
17
        'prev_sibling' => 'previousSibling',
18
        'parent'       => 'parentNode',
19
        'outertext'    => 'html',
20
        'outerhtml'    => 'html',
21
        'innertext'    => 'innerHtml',
22
        'innerhtml'    => 'innerHtml',
23
        'innerhtmlkeep'    => 'innerHtmlKeep',
24
    ];
25

26
    /**
27
     * @var string[]
28
     */
29
    protected static $stringDomNodes = [
30
        'id',
31
        'prefix',
32
        'content'
33
    ];
34

35
    /**
36
     * @var \DOMElement|\DOMNode|null
37
     */
38
    protected $node;
39

40
    /**
41
     * @var SimpleHtmlAttributes|null
42
     */
43
    private $classListCache;
44

45
    /**
46
     * @param string $name
47
     * @param array  $arguments
48
     *
49
     * @throws \BadMethodCallException
50
     *
51
     * @return SimpleHtmlDomInterface|string|null
52
     */
53
    public function __call($name, $arguments)
54
    {
55
        $name = \strtolower($name);
×
56

57
        if (isset(self::$functionAliases[$name])) {
×
58
            return \call_user_func_array([$this, self::$functionAliases[$name]], $arguments);
×
59
        }
60

61
        throw new \BadMethodCallException('Method does not exist');
×
62
    }
63

64
    /**
65
     * @param string $name
66
     *
67
     * @return SimpleHtmlAttributes|string|string[]|null
68
     */
69
    public function __get($name)
70
    {
71
        $nameOrig = $name;
686✔
72
        $name = \strtolower($name);
686✔
73

74
        switch ($name) {
75
            case 'outerhtml':
686✔
76
            case 'outertext':
630✔
77
            case 'html':
546✔
78
                return $this->html();
210✔
79
            case 'innerhtml':
546✔
80
            case 'innertext':
462✔
81
                return $this->innerHtml();
147✔
82
            case 'innerhtmlkeep':
420✔
83
                return $this->innerHtml(false, false);
7✔
84
            case 'text':
420✔
85
            case 'plaintext':
378✔
86
                return $this->text();
224✔
87
            case 'tag':
224✔
88
                return $this->node->nodeName ?? '';
42✔
89
            case 'attr':
203✔
90
                return $this->getAllAttributes();
×
91
            case 'classlist':
203✔
92
                if ($this->classListCache === null) {
84✔
93
                    $this->classListCache = new SimpleHtmlAttributes($this->node ?? null, 'class');
84✔
94
                }
95

96
                return $this->classListCache;
84✔
97
            default:
98
                if ($this->node && \property_exists($this->node, $nameOrig)) {
119✔
99
                    if (\is_string($this->node->{$nameOrig})) {
32✔
100
                        return HtmlDomParser::putReplacedBackToPreserveHtmlEntities($this->node->{$nameOrig});
32✔
101
                    }
102

103
                    return $this->node->{$nameOrig};
×
104
                }
105

106
                return $this->getAttribute($name);
105✔
107
        }
108
    }
109

110
    /**
111
     * @param string $selector
112
     * @param int    $idx
113
     *
114
     * @return SimpleHtmlDomInterface|SimpleHtmlDomInterface[]|SimpleHtmlDomNodeInterface<SimpleHtmlDomInterface>
115
     */
116
    public function __invoke($selector, $idx = null)
117
    {
118
        return $this->find($selector, $idx);
84✔
119
    }
120

121
    /**
122
     * @param string $name
123
     *
124
     * @return bool
125
     */
126
    public function __isset($name)
127
    {
128
        $nameOrig = $name;
7✔
129
        $name = \strtolower($name);
7✔
130

131
        switch ($name) {
132
            case 'outertext':
7✔
133
            case 'outerhtml':
7✔
134
            case 'innertext':
7✔
135
            case 'innerhtml':
7✔
136
            case 'innerhtmlkeep':
7✔
137
            case 'plaintext':
7✔
138
            case 'text':
7✔
139
            case 'tag':
7✔
140
                return true;
×
141
            default:
142
                if ($this->node && \property_exists($this->node, $nameOrig)) {
7✔
UNCOV
143
                    return isset($this->node->{$nameOrig});
2✔
144
                }
145

146
                return $this->hasAttribute($name);
5✔
147
        }
148
    }
149

150
    /**
151
     * @param string $name
152
     * @param mixed  $value
153
     *
154
     * @return SimpleHtmlDomInterface|null
155
     */
156
    public function __set($name, $value)
157
    {
158
        $nameOrig = $name;
209✔
159
        $name = \strtolower($name);
209✔
160

161
        switch ($name) {
162
            case 'outerhtml':
209✔
163
            case 'outertext':
181✔
164
                return $this->replaceNodeWithString($value);
70✔
165
            case 'innertext':
139✔
166
            case 'innerhtml':
119✔
167
                return $this->replaceChildWithString($value);
62✔
168
            case 'innerhtmlkeep':
105✔
169
                return $this->replaceChildWithString($value, false);
7✔
170
            case 'plaintext':
98✔
171
                return $this->replaceTextWithString($value);
7✔
172
            case 'classlist':
91✔
173
                $name = 'class';
7✔
174
                $nameOrig = 'class';
7✔
175
                // no break
176
            default:
177
                if ($this->node && \property_exists($this->node, $nameOrig)) {
91✔
178
                    // INFO: Cannot assign null to property DOMNode::* of type string
UNCOV
179
                    if (in_array($nameOrig, self::$stringDomNodes)) {
2✔
UNCOV
180
                        $value = (string)$value;
2✔
181
                    }
182

UNCOV
183
                    if (!is_null($value)) {
2✔
UNCOV
184
                        return $this->node->{$nameOrig} = $value;
2✔
185
                    }
186
                }
187

188
                return $this->setAttribute($name, $value);
91✔
189
        }
190
    }
191

192
    /**
193
     * @return string
194
     */
195
    public function __toString()
196
    {
197
        return $this->html();
21✔
198
    }
199

200
    /**
201
     * @param string $name
202
     *
203
     * @return void
204
     */
205
    public function __unset($name)
206
    {
207
        /** @noinspection UnusedFunctionResultInspection */
208
        $this->removeAttribute($name);
×
209
    }
210

211
    /**
212
     * @param string $selector
213
     * @param int|null   $idx
214
     *
215
     * @return mixed
216
     */
217
    abstract public function find(string $selector, $idx = null);
218

219
    /**
220
     * @return string[]|null
221
     */
222
    abstract public function getAllAttributes();
223

224
    abstract public function getAttribute(string $name): string;
225

226
    abstract public function hasAttribute(string $name): bool;
227

228
    abstract public function html(bool $multiDecodeNewHtmlEntity = false): string;
229

230
    abstract public function innerHtml(bool $multiDecodeNewHtmlEntity = false, bool $putBrokenReplacedBack = true): string;
231

232
    abstract public function removeAttribute(string $name): SimpleHtmlDomInterface;
233

234
    abstract protected function replaceChildWithString(string $string, bool $putBrokenReplacedBack = true): SimpleHtmlDomInterface;
235

236
    abstract protected function replaceNodeWithString(string $string): SimpleHtmlDomInterface;
237

238
    /**
239
     * @param string $string
240
     *
241
     * @return SimpleHtmlDomInterface
242
     */
243
    abstract protected function replaceTextWithString($string): SimpleHtmlDomInterface;
244

245
    /**
246
     * @param string      $name
247
     * @param string|null $value
248
     * @param bool        $strictEmptyValueCheck
249
     *
250
     * @return SimpleHtmlDomInterface
251
     */
252
    abstract public function setAttribute(string $name, $value = null, bool $strictEmptyValueCheck = false): SimpleHtmlDomInterface;
253

254
    abstract public function text(): string;
255
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc