1 | <?php |
||
24 | class XMLReader |
||
25 | { |
||
26 | /** |
||
27 | * DOMDocument object |
||
28 | * |
||
29 | * @var \DOMDocument |
||
30 | */ |
||
31 | private $dom = null; |
||
32 | |||
33 | /** |
||
34 | * DOMXpath object |
||
35 | * |
||
36 | * @var \DOMXpath |
||
37 | */ |
||
38 | private $xpath = null; |
||
39 | |||
40 | /** |
||
41 | * Get DOMDocument from ZipArchive |
||
42 | * |
||
43 | * @param string $zipFile |
||
44 | * @param string $xmlFile |
||
45 | * @return \DOMDocument|false |
||
46 | * @throws \Exception |
||
47 | */ |
||
48 | 2 | public function getDomFromZip($zipFile, $xmlFile) |
|
49 | { |
||
50 | 2 | if (file_exists($zipFile) === false) { |
|
51 | 1 | throw new \Exception('Cannot find archive file.'); |
|
52 | } |
||
53 | |||
54 | 1 | $zip = new \ZipArchive(); |
|
55 | 1 | $zip->open($zipFile); |
|
56 | 1 | $content = $zip->getFromName($xmlFile); |
|
57 | 1 | $zip->close(); |
|
58 | |||
59 | 1 | if ($content === false) { |
|
60 | 1 | return false; |
|
61 | } |
||
62 | |||
63 | 1 | return $this->getDomFromString($content); |
|
64 | } |
||
65 | |||
66 | /** |
||
67 | * Get DOMDocument from content string |
||
68 | * |
||
69 | * @param string $content |
||
70 | * @return \DOMDocument |
||
71 | */ |
||
72 | 6 | public function getDomFromString($content) |
|
79 | |||
80 | /** |
||
81 | * Get elements |
||
82 | * |
||
83 | * @param string $path |
||
84 | * @param \DOMElement $contextNode |
||
85 | * @return \DOMNodeList |
||
86 | */ |
||
87 | 6 | public function getElements($path, \DOMElement $contextNode = null) |
|
88 | { |
||
89 | 6 | if ($this->dom === null) { |
|
90 | 1 | return array(); |
|
|
|||
91 | } |
||
92 | 6 | if ($this->xpath === null) { |
|
93 | 5 | $this->xpath = new \DOMXpath($this->dom); |
|
94 | 5 | } |
|
95 | |||
96 | 6 | if (is_null($contextNode)) { |
|
97 | 6 | return $this->xpath->query($path); |
|
98 | } |
||
99 | |||
100 | 1 | return $this->xpath->query($path, $contextNode); |
|
101 | } |
||
102 | |||
103 | /** |
||
104 | * Registers the namespace with the DOMXPath object |
||
105 | * |
||
106 | * @param string $prefix The prefix |
||
107 | * @param string $namespaceURI The URI of the namespace |
||
108 | * @return bool true on success or false on failure |
||
109 | * @throws \InvalidArgumentException If called before having loaded the DOM document |
||
110 | */ |
||
111 | 2 | public function registerNamespace($prefix, $namespaceURI) |
|
112 | { |
||
113 | 2 | if ($this->dom === null) { |
|
114 | 1 | throw new \InvalidArgumentException('Dom needs to be loaded before registering a namespace'); |
|
115 | } |
||
116 | 1 | if ($this->xpath === null) { |
|
117 | 1 | $this->xpath = new \DOMXpath($this->dom); |
|
118 | 1 | } |
|
119 | 1 | return $this->xpath->registerNamespace($prefix, $namespaceURI); |
|
120 | } |
||
121 | |||
122 | /** |
||
123 | * Get element |
||
124 | * |
||
125 | * @param string $path |
||
126 | * @param \DOMElement $contextNode |
||
127 | * @return \DOMElement|null |
||
128 | */ |
||
129 | 3 | public function getElement($path, \DOMElement $contextNode = null) |
|
130 | { |
||
131 | 3 | $elements = $this->getElements($path, $contextNode); |
|
132 | 3 | if ($elements->length > 0) { |
|
133 | 2 | return $elements->item(0); |
|
134 | } |
||
135 | |||
136 | 1 | return null; |
|
137 | } |
||
138 | |||
139 | /** |
||
140 | * Get element attribute |
||
141 | * |
||
142 | * @param string $attribute |
||
143 | * @param \DOMElement $contextNode |
||
144 | * @param string $path |
||
145 | * @return string|null |
||
146 | */ |
||
147 | 1 | public function getAttribute($attribute, \DOMElement $contextNode = null, $path = null) |
|
148 | { |
||
149 | 1 | $return = null; |
|
150 | 1 | if ($path !== null) { |
|
151 | 1 | $elements = $this->getElements($path, $contextNode); |
|
152 | 1 | if ($elements->length > 0) { |
|
153 | /** @var \DOMElement $node Type hint */ |
||
154 | 1 | $node = $elements->item(0); |
|
155 | 1 | $return = $node->getAttribute($attribute); |
|
156 | 1 | } |
|
157 | 1 | } else { |
|
158 | 1 | if ($contextNode !== null) { |
|
159 | 1 | $return = $contextNode->getAttribute($attribute); |
|
160 | 1 | } |
|
161 | } |
||
162 | |||
163 | 1 | return ($return == '') ? null : $return; |
|
164 | } |
||
165 | |||
166 | /** |
||
167 | * Get element value |
||
168 | * |
||
169 | * @param string $path |
||
170 | * @param \DOMElement $contextNode |
||
171 | * @return string|null |
||
172 | */ |
||
173 | 2 | public function getValue($path, \DOMElement $contextNode = null) |
|
174 | { |
||
175 | 2 | $elements = $this->getElements($path, $contextNode); |
|
176 | 2 | if ($elements->length > 0) { |
|
177 | 1 | return $elements->item(0)->nodeValue; |
|
178 | } |
||
179 | |||
180 | 1 | return null; |
|
181 | } |
||
182 | |||
183 | /** |
||
184 | * Count elements |
||
185 | * |
||
186 | * @param string $path |
||
187 | * @param \DOMElement $contextNode |
||
188 | * @return integer |
||
189 | */ |
||
190 | 1 | public function countElements($path, \DOMElement $contextNode = null) |
|
196 | |||
197 | /** |
||
198 | * Element exists |
||
199 | * |
||
200 | * @param string $path |
||
201 | * @param \DOMElement $contextNode |
||
202 | * @return boolean |
||
203 | */ |
||
204 | 4 | public function elementExists($path, \DOMElement $contextNode = null) |
|
208 | } |
||
209 |
If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.
Let’s take a look at an example:
Our function
my_function
expects aPost
object, and outputs the author of the post. The base classPost
returns a simple string and outputting a simple string will work just fine. However, the child classBlogPost
which is a sub-type ofPost
instead decided to return anobject
, and is therefore violating the SOLID principles. If aBlogPost
were passed tomy_function
, PHP would not complain, but ultimately fail when executing thestrtoupper
call in its body.