Passed
Push — master ( e57079...36e9b4 )
by Gilles
02:49
created

HtmlNode::getIteratorArray()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 1 Features 1
Metric Value
c 2
b 1
f 1
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
namespace PHPHtmlParser\Dom;
3
4
use PHPHtmlParser\Exceptions\UnknownChildTypeException;
5
use PHPHtmlParser\Exceptions\ChildNotFoundException;
6
7
/**
8
 * Class HtmlNode
9
 *
10
 * @package PHPHtmlParser\Dom
11
 */
12
class HtmlNode extends ArrayNode
13
{
14
15
    /**
16
     * Remembers what the innerHtml was if it was scanned previously.
17
     */
18
    protected $innerHtml = null;
19
20
    /**
21
     * Remembers what the outerHtml was if it was scanned previously.
22
     *
23
     * @var string
24
     */
25
    protected $outerHtml = null;
26
27
    /**
28
     * Remembers what the text was if it was scanned previously.
29
     *
30
     * @var string
31
     */
32
    protected $text = null;
33
34
    /**
35
     * Remembers what the text was when we looked into all our
36
     * children nodes.
37
     *
38
     * @var string
39
     */
40
    protected $textWithChildren = null;
41
42
    /**
43
     * Sets up the tag of this node.
44
     *
45
     * @param $tag
46
     */
47
    public function __construct($tag)
48
    {
49
        if ( ! $tag instanceof Tag) {
50
            $tag = new Tag($tag);
51
        }
52
        $this->tag = $tag;
53
        parent::__construct();
54
    }
55
56
    /**
57
     * Gets the inner html of this node.
58
     *
59
     * @return string
60
     * @throws UnknownChildTypeException
61
     */
62
    public function innerHtml()
63
    {
64
        if ( ! $this->hasChildren()) {
65
            // no children
66
            return '';
67
        }
68
69
        if ( ! is_null($this->innerHtml)) {
70
            // we already know the result.
71
            return $this->innerHtml;
72
        }
73
74
        $child  = $this->firstChild();
75
        $string = '';
76
77
        // continue to loop until we are out of children
78
        while ( ! is_null($child)) {
79
            if ($child instanceof TextNode) {
80
                $string .= $child->text();
81
            } elseif ($child instanceof HtmlNode) {
82
                $string .= $child->outerHtml();
83
            } else {
84
                throw new UnknownChildTypeException('Unknown child type "'.get_class($child).'" found in node');
85
            }
86
87
            try {
88
                $child = $this->nextChild($child->id());
89
            } catch (ChildNotFoundException $e) {
90
                // no more children
91
                $child = null;
92
            }
93
        }
94
95
        // remember the results
96
        $this->innerHtml = $string;
97
98
        return $string;
99
    }
100
101
    /**
102
     * Gets the html of this node, including it's own
103
     * tag.
104
     *
105
     * @return string
106
     */
107
    public function outerHtml()
108
    {
109
        // special handling for root
110
        if ($this->tag->name() == 'root') {
111
            return $this->innerHtml();
112
        }
113
114
        if ( ! is_null($this->outerHtml)) {
115
            // we already know the results.
116
            return $this->outerHtml;
117
        }
118
119
        $return = $this->tag->makeOpeningTag();
120
        if ($this->tag->isSelfClosing()) {
121
            // ignore any children... there should not be any though
122
            return $return;
123
        }
124
125
        // get the inner html
126
        $return .= $this->innerHtml();
127
128
        // add closing tag
129
        $return .= $this->tag->makeClosingTag();
130
131
        // remember the results
132
        $this->outerHtml = $return;
133
134
        return $return;
135
    }
136
137
    /**
138
     * Gets the text of this node (if there is any text). Or get all the text
139
     * in this node, including children.
140
     *
141
     * @param bool $lookInChildren
142
     * @return string
143
     */
144
    public function text($lookInChildren = false)
145
    {
146
        if ($lookInChildren) {
147
            if ( ! is_null($this->textWithChildren)) {
148
                // we already know the results.
149
                return $this->textWithChildren;
150
            }
151
        } elseif ( ! is_null($this->text)) {
152
            // we already know the results.
153
            return $this->text;
154
        }
155
156
        // find out if this node has any text children
157
        $text = '';
158
        foreach ($this->children as $child) {
159
            /** @var AbstractNode $node */
160
            $node = $child['node'];
161
            if ($node instanceof TextNode) {
162
                $text .= $child['node']->text;
163
            } elseif ($lookInChildren and
0 ignored issues
show
Comprehensibility Best Practice introduced by
Using logical operators such as and instead of && is generally not recommended.

PHP has two types of connecting operators (logical operators, and boolean operators):

  Logical Operators Boolean Operator
AND - meaning and &&
OR - meaning or ||

The difference between these is the order in which they are executed. In most cases, you would want to use a boolean operator like &&, or ||.

Let’s take a look at a few examples:

// Logical operators have lower precedence:
$f = false or true;

// is executed like this:
($f = false) or true;


// Boolean operators have higher precedence:
$f = false || true;

// is executed like this:
$f = (false || true);

Logical Operators are used for Control-Flow

One case where you explicitly want to use logical operators is for control-flow such as this:

$x === 5
    or die('$x must be 5.');

// Instead of
if ($x !== 5) {
    die('$x must be 5.');
}

Since die introduces problems of its own, f.e. it makes our code hardly testable, and prevents any kind of more sophisticated error handling; you probably do not want to use this in real-world code. Unfortunately, logical operators cannot be combined with throw at this point:

// The following is currently a parse error.
$x === 5
    or throw new RuntimeException('$x must be 5.');

These limitations lead to logical operators rarely being of use in current PHP code.

Loading history...
164
                $node instanceof HtmlNode
165
            ) {
166
                $text .= $node->text($lookInChildren);
167
            }
168
        }
169
170
        // remember our result
171
        if ($lookInChildren) {
172
            $this->textWithChildren = $text;
173
        } else {
174
            $this->text = $text;
175
        }
176
177
        return $text;
178
    }
179
180
    /**
181
     * Call this when something in the node tree has changed. Like a child has been added
182
     * or a parent has been changed.
183
     */
184
    protected function clear()
185
    {
186
        $this->innerHtml = null;
187
        $this->outerHtml = null;
188
        $this->text      = null;
189
    }
190
191
    /**
192
     * Returns all children of this html node.
193
     *
194
     * @return array
195
     */
196
    protected function getIteratorArray()
197
    {
198
        return $this->getChildren();
199
    }
200
}
201