Completed
Pull Request — master (#6)
by Tim
04:18
created

Configuration::setPosition()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 3
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 1
1
<?php
2
3
/**
4
 * \AppserverIo\Configuration\Configuration
5
 *
6
 * NOTICE OF LICENSE
7
 *
8
 * This source file is subject to the Open Software License (OSL 3.0)
9
 * that is available through the world-wide-web at this URL:
10
 * http://opensource.org/licenses/osl-3.0.php
11
 *
12
 * PHP version 5
13
 *
14
 * @author     Tim Wagner <[email protected]>
15
 * @copyright  2015 TechDivision GmbH <[email protected]>
16
 * @license    http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
17
 * @link       http://github.com/appserver-io/configuration
18
 * @link       http://www.appserver.io
19
 */
20
21
namespace AppserverIo\Configuration;
22
23
use AppserverIo\Configuration\Interfaces\ConfigurationInterface;
24
use AppserverIo\Configuration\Interfaces\PersistableConfigurationInterface;
25
use AppserverIo\Configuration\Interfaces\ValidityAwareConfigurationInterface;
26
27
/**
28
 * A simple XML based configuration implementation.
29
 *
30
 * @author     Tim Wagner <[email protected]>
31
 * @copyright  2015 TechDivision GmbH <[email protected]>
32
 * @license    http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
33
 * @link       http://github.com/appserver-io/configuration
34
 * @link       http://www.appserver.io
35
 */
36
class Configuration implements ConfigurationInterface, ValidityAwareConfigurationInterface, PersistableConfigurationInterface
37
{
38
39
    /**
40
     * XSD schema filename used for validation.
41
     *
42
     * @var string
43
     */
44
    protected $schemaFile;
45
46
    /**
47
     * the node name to use.
48
     *
49
     * @var string
50
     */
51
    protected $nodeName;
52
53
    /**
54
     * The node's position in the tree.
55
     *
56
     * @var integer
57
     */
58
    protected $position = 0;
59
60
    /**
61
     * The node value.
62
     *
63
     * @var string
64
     */
65
    protected $value;
66
67
    /**
68
     * The array with configuration parameters.
69
     *
70
     * @var array
71
     */
72
    protected $data = array();
73
74
    /**
75
     * The array with the child configurations.
76
     *
77
     * @var array
78
     */
79
    protected $children = array();
80
81
    /**
82
     * Initializes the configuration with the node name of the
83
     * node in the XML structure.
84
     *
85
     * @param string|null $nodeName The configuration element's node name
86
     * @param integer     $position The node's position in the tree
87
     */
88 23
    public function __construct($nodeName = null, $position = 0)
89
    {
90 23
        $this->setNodeName($nodeName);
91 23
        $this->setPosition($position);
92 23
    }
93
94
    /**
95
     * Sets the configuration element's node name.
96
     *
97
     * @param string $nodeName The node name
98
     *
99
     * @return \AppserverIo\Configuration\Interfaces\ConfigurationInterface The instance itself
100
     */
101 23
    public function setNodeName($nodeName)
102
    {
103 23
        $this->nodeName = $nodeName;
104 23
    }
105
106
    /**
107
     * Returns the configuration element's node name.
108
     *
109
     * @return string The node name
110
     */
111 12
    public function getNodeName()
112
    {
113 12
        return $this->nodeName;
114
    }
115
116
    /**
117
     * Sets the position of the node in the tree.
118
     *
119
     * @param integer $position The node's position
120
     *
121
     * @return void
122
     */
123 23
    public function setPosition($position)
124
    {
125 23
        $this->position = $position;
126 23
    }
127
128
    /**
129
     * Returns the position of the node in the tree.
130
     *
131
     * @return integer The node's position
132
     */
133 1
    public function getPosition()
134
    {
135 1
        return $this->position;
136
    }
137
138
    /**
139
     * Checks if the passed configuration is equal. If yes, the method
140
     * returns TRUE, if not FALSE.
141
     *
142
     * @param \AppserverIo\Configuration\Interfaces\ConfigurationInterface $configuration The configuration to compare to
143
     *
144
     * @return boolean TRUE if the configurations are equal, else FALSE
145
     */
146 2
    public function equals(ConfigurationInterface $configuration)
147
    {
148 2
        return $this === $configuration;
149
    }
150
151
    /**
152
     * Adds a new child configuration.
153
     *
154
     * @param \AppserverIo\Configuration\Interfaces\ConfigurationInterface $configuration The child configuration itself
155
     *
156
     * @return \AppserverIo\Configuration\Interfaces\ConfigurationInterface The configuration instance
157
     */
158 17
    public function addChild(ConfigurationInterface $configuration)
159
    {
160 17
        $this->children[] = $configuration;
161 17
        return $this;
162
    }
163
164
    /**
165
     * Creates a new child configuration node with the passed name and value
166
     * and adds it as child to this node.
167
     *
168
     * @param string $nodeName The child's node name
169
     * @param string $value    The child's node value
170
     *
171
     * @return void
172
     */
173
    public function addChildWithNameAndValue($nodeName, $value)
174
    {
175
        $node = new Configuration();
176
        $node->setNodeName($nodeName);
177
        $node->setValue($value);
178
        $this->addChild($node);
179
    }
180
181
    /**
182
     * Initializes the configuration with the XML information found
183
     * in the file with the passed relative or absolute path.
184
     *
185
     * @param string $file The path to the file
186
     *
187
     * @return \AppserverIo\Configuration\Interfaces\ConfigurationInterface The initialized configuration
188
     * @throws \Exception Is thrown if the file with the passed name is not a valid XML file
189
     */
190 4 View Code Duplication
    public function initFromFile($file)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
191
    {
192 4
        if (($root = simplexml_load_file($file)) === false) {
193
            $errors = array();
194
            foreach (libxml_get_errors() as $error) {
195
                $errors[] = sprintf(
196
                    'Found a schema validation error on line %s with code %s and message %s when validating configuration file %s',
197
                    $error->line,
198
                    $error->code,
199
                    $error->message,
200
                    $error->file
201
                );
202
            }
203
            throw new \Exception(implode(PHP_EOL, $errors));
204
        }
205 4
        return $this->init($root);
206
    }
207
208
    /**
209
     * Initializes the configuration with the XML information passed as string.
210
     *
211
     * @param string $string The string with the XML content to initialize from
212
     *
213
     * @return \AppserverIo\Configuration\Interfaces\ConfigurationInterface The initialized configuration
214
     * @throws \Exception Is thrown if the passed XML string is not valid
215
     */
216 View Code Duplication
    public function initFromString($string)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
217
    {
218
        if (($root = simplexml_load_string($string)) === false) {
219
            $errors = array();
220
            foreach (libxml_get_errors() as $error) {
221
                $errors[] = sprintf(
222
                    'Found a schema validation error on line %s with code %s and message %s when validating configuration file %s',
223
                    $error->line,
224
                    $error->code,
225
                    $error->message,
226
                    $error->file
227
                );
228
            }
229
            throw new \Exception(implode(PHP_EOL, $errors));
230
        }
231
        return $this->init($root);
232
    }
233
234
    /**
235
     * Initializes the configuration with the XML information found
236
     * in the passed DOMDocument.
237
     *
238
     * @param \DOMDocument $domDocument The DOMDocument with XML information
239
     *
240
     * @return \AppserverIo\Configuration\Interfaces\ConfigurationInterface The initialized configuration
241
     */
242 1
    public function initFromDomDocument(\DOMDocument $domDocument)
243
    {
244 1
        $root = simplexml_import_dom($domDocument);
245 1
        return $this->init($root);
246
    }
247
248
    /**
249
     * Recursively initializes the configuration instance with the data from the
250
     * passed SimpleXMLElement.
251
     *
252
     * @param \SimpleXMLElement $node The node to load the data from
253
     *
254
     * @return \AppserverIo\Configuration\Interfaces\ConfigurationInterface The node instance itself
255
     */
256 15
    public function init(\SimpleXMLElement $node)
257
    {
258
259
        // set the node name + value
260 15
        $this->setNodeName($node->getName());
261
262
        // check if we found a node value
263 15
        $nodeValue = (string) $node;
264 15
        if (empty($nodeValue) === false) {
265 15
            $this->setValue(trim($nodeValue));
266
        }
267
268
        // load the attributes
269 15
        foreach ($node->attributes() as $key => $value) {
270 14
            $this->setData($key, (string) $value);
271
        }
272
273
        // initialize the position counter
274 15
        $position = 0;
275
276
        // append children
277 15
        foreach ($node->children() as $child) {
278
            // create a new configuration node
279 15
            $cnt = new Configuration(null, $position++);
280
281
            // parse the configuration recursive
282 15
            $cnt->init($child);
283
284
            // append the configuration node to the parent
285 15
            $this->addChild($cnt);
286
        }
287
288
        // return the instance node itself
289 15
        return $this;
290
    }
291
292
    /**
293
     * Returns the child configuration nodes with the passed type.
294
     *
295
     * @param string $path The path of the configuration to return
296
     *
297
     * @return array The requested child configuration nodes
298
     */
299 9
    public function getChilds($path)
300
    {
301 9
        $token = strtok($path, '/');
302 9
        $next = substr($path, strlen('/' . $token));
303 9
        if ($this->getNodeName() == $token && empty($next)) {
304 7
            return $this;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $this; (AppserverIo\Configuration\Configuration) is incompatible with the return type declared by the interface AppserverIo\Configuratio...ionInterface::getChilds of type array.

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:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
305 9
        } elseif ($this->getNodeName() == $token && empty($next) === false) {
306 7
            $matches = array();
307 7
            foreach ($this->getChildren() as $child) {
308 7
                $result = $child->getChilds($next);
309 7
                if (is_array($result)) {
310 4
                    $matches = $result;
311 7
                } elseif ($result instanceof Configuration) {
312 7
                    $matches[] = $result;
313
                }
314
            }
315 7
            return $matches;
316
        } else {
317 6
            return null;
318
        }
319
    }
320
321
    /**
322
     * Returns the child configuration with the passed type.
323
     *
324
     * @param string $path The path of the configuration to return
325
     *
326
     * @return \AppserverIo\Configuration\Interfaces\ConfigurationInterface The requested configuration
327
     */
328 9
    public function getChild($path)
329
    {
330 9
        if (is_array($childs = $this->getChilds($path))) {
331 7
            return current($childs);
332
        }
333 2
    }
334
335
    /**
336
     * Removes the children of the configuration with passed path and
337
     * returns the parent configuration.
338
     *
339
     * @param string $path The path of the configuration to remove the children for
340
     *
341
     * @return \AppserverIo\Configuration\Interfaces\ConfigurationInterface The instance the children has been removed
342
     * @see \AppserverIo\Configuration\Interfaces\ConfigurationInterface::getChild($path)
343
     * @see \AppserverIo\Configuration\Interfaces\ConfigurationInterface::getChilds($path)
344
     */
345 3
    public function removeChilds($path)
346
    {
347 3
        $token = strtok($path, '/');
348 3
        $next = substr($path, strlen('/' . $token));
349 3
        if ($this->getNodeName() == $token && empty($next) === false) {
350 2
            $this->setChildren(array());
351 2
            return $this;
352
        } else {
353 1
            return $this;
354
        }
355
    }
356
357
    /**
358
     * Returns all child configurations.
359
     *
360
     * @return array The child configurations
361
     */
362 16
    public function getChildren()
363
    {
364 16
        return $this->children;
365
    }
366
367
    /**
368
     * Replaces actual children with the passed array. If children
369
     * already exists they will be lost.
370
     *
371
     * @param array $children The array with the children to set
372
     *
373
     * @return void
374
     */
375 2
    public function setChildren(array $children)
376
    {
377 2
        $this->children = $children;
378 2
    }
379
380
    /**
381
     * Check's if the node has children, if yes the method
382
     * returns TRUE, else the method returns FALSE.
383
     *
384
     * @return boolean TRUE if the node has children, else FALSE
385
     */
386 9
    public function hasChildren()
387
    {
388
        // check the children size
389 9
        if (sizeof($this->getChildren()) == 0) {
390 3
            return false;
391
        }
392 8
        return true;
393
    }
394
395
    /**
396
     * Adds the passed configuration value.
397
     *
398
     * @param string $key   Name of the configuration value
399
     * @param mixed  $value The configuration value
400
     *
401
     * @return void
402
     */
403 15
    public function setData($key, $value)
404
    {
405 15
        $this->data[$key] = $value;
406 15
    }
407
408
    /**
409
     * Returns the configuration value with the passed name.
410
     *
411
     * @param string $key The name of the requested configuration value.
412
     *
413
     * @return mixed The configuration value itself
414
     */
415 4
    public function getData($key)
416
    {
417 4
        if (array_key_exists($key, $this->data)) {
418 2
            return $this->data[$key];
419
        }
420 2
    }
421
422
    /**
423
     * Appends the passed attributes to the configuration node. If the
424
     * attribute already exists it will be overwritten by default.
425
     *
426
     * @param array $data The data with the attributes to append
427
     *
428
     * @return void
429
     */
430
    public function appendData(array $data)
431
    {
432
        foreach ($data as $key => $value) {
433
            $this->data[$key] = $value;
434
        }
435
    }
436
437
    /**
438
     * Replaces actual attributes with the passed array. If attributes
439
     * already exists they will be lost.
440
     *
441
     * @param array $data The array with the key value attribute pairs
442
     *
443
     * @return void
444
     */
445 2
    public function setAllData($data)
446
    {
447 2
        $this->data = $data;
448 2
    }
449
450
    /**
451
     * Returns all attributes.
452
     *
453
     * @return array The array with all attributes
454
     */
455 2
    public function getAllData()
456
    {
457 2
        return $this->data;
458
    }
459
460
    /**
461
     * Wrapper method for getter/setter methods.
462
     *
463
     * @param string $method The called method name
464
     * @param array  $args   The methods arguments
465
     *
466
     * @return mixed The value if a getter has been invoked
467
     * @throws \Exception Is thrown if nor a getter/setter has been invoked
468
     */
469 5
    public function __call($method, $args)
470
    {
471
        // lowercase the first character of the member
472 5
        $key = lcfirst(substr($method, 3));
473
        // check if a getter/setter has been called
474 5
        switch (substr($method, 0, 3)) {
475 5
            case 'get':
476 3
                $child = $this->getChild("/{$this->getNodeName()}/$key");
477 3
                if ($child instanceof Configuration) {
478 2
                    return $child;
479
                }
480 2
                return $this->getData($key);
481 2
            case 'set':
482 1
                $this->setData($key, isset($args[0]) ? $args[0] : null);
483 1
                break;
484
            default:
485 1
                throw new \Exception("Invalid method " . get_class($this) . "::" . $method . "(" . print_r($args, true) . ")");
486
        }
487 1
    }
488
489
    /**
490
     * Sets the configuration node's value e.g. <node>VALUE</node>.
491
     *
492
     * @param string $value The node's value
493
     *
494
     * @return void
495
     */
496 15
    public function setValue($value)
497
    {
498 15
        $this->value = $value;
499 15
    }
500
501
    /**
502
     * Returns the configuration node's value.
503
     *
504
     * @return string The node's value
505
     */
506 4
    public function getValue()
507
    {
508 4
        return $this->value;
509
    }
510
511
    /**
512
     * Returns the configuration node's value.
513
     *
514
     * @return string The configuration node's value
515
     */
516 2
    public function __toString()
517
    {
518 2
        return $this->getValue();
519
    }
520
521
    /**
522
     * Merge the configuration
523
     *
524
     * @param \AppserverIo\Configuration\Interfaces\ConfigurationInterface $configuration A configuration to merge
525
     *
526
     * @return \AppserverIo\Configuration\Interfaces\ConfigurationInterface The instance
527
     */
528 2
    public function merge(ConfigurationInterface $configuration)
529
    {
530 2
        if ($this->hasSameSignature($configuration)) {
531 2
            $this->setValue($configuration->getValue());
532 2
            $this->setAllData($configuration->getAllData());
533 2
            if ($configuration->hasChildren()) {
534 2
                foreach ($configuration->getChildren() as $child) {
535 2
                    $path = $this->getNodeName() . "/" . $child->getNodeName();
536 2
                    if ($this->getChild($path)) {
537 2
                        if ($newChild = $this->getChild($path)->merge($child)) {
538 2
                            $this->addChild($newChild);
539
                        }
540
                    } else {
541 2
                        $this->addChild($child);
542
                    }
543
                }
544
            }
545
        } else {
546 2
            return $configuration;
547
        }
548 2
    }
549
550
    /**
551
     * Merges this configuration element with the data found in the passed configuration file.
552
     *
553
     * @param string $file The path to the file we want to merge
554
     *
555
     * @return \AppserverIo\Configuration\Interfaces\ConfigurationInterface The configuration created from the passed file
556
     */
557
    public function mergeFromFile($file)
558
    {
559
560
        // initialize a new configuration instance
561
        $configuration = new Configuration();
562
        $configuration->initFromFile($file);
563
564
        // merge the instance with this one
565
        $this->merge($configuration);
566
567
        // return this instance
568
        return $configuration;
569
    }
570
571
    /**
572
     * Merges this configuration element with the passed configuration data.
573
     *
574
     * @param string $string The string with the XML content to initialize from
575
     *
576
     * @return \AppserverIo\Configuration\Interfaces\ConfigurationInterface The configuration created from the passed string
577
     */
578
    public function mergeFromString($string)
579
    {
580
581
        // initialize a new configuration instance
582
        $configuration = new Configuration();
583
        $configuration->initFromString($string);
584
585
        // merge the instance with this one
586
        $this->merge($configuration);
587
588
        // return this instance
589
        return $configuration;
590
    }
591
592
    /**
593
     * Returns the node signature using a md5 hash based on
594
     * the node name and the param data.
595
     *
596
     * @return string The node signature as md5 hash
597
     */
598 2
    public function getSignature()
599
    {
600 2
        return md5($this->getNodeName() . implode('', $this->getAllData()));
601
    }
602
603
    /**
604
     * Returns TRUE if the node signatures are equals, else FALSE
605
     *
606
     * @param \AppserverIo\Configuration\Interfaces\ConfigurationInterface $configuration The configuration node to check the signature
607
     *
608
     * @return boolean TRUE if the signature of the passed node equals the signature of this instance, else FALSE
609
     */
610 2
    public function hasSameSignature(ConfigurationInterface $configuration)
611
    {
612 2
        return $this->getSignature() === $configuration->getSignature();
613
    }
614
615
    /**
616
     * Saves the configuration node recursively to the
617
     * file with the passed name.
618
     *
619
     * @param string $filename The filename to save the configuration node to
620
     *
621
     * @return void
622
     */
623
    public function save($filename)
624
    {
625
        $this->toDomDocument()->save($filename);
626
    }
627
628
    /**
629
     * Creates and returns a DOM document by recursively parsing
630
     * the configuration node and it's childs.
631
     *
632
     * @param string $namespaceURI The dom document namespace
633
     *
634
     * @return \DOMDocument The configuration node as DOM document
635
     */
636
    public function toDomDocument($namespaceURI = 'http://www.appserver.io/appserver')
637
    {
638
        $domDocument = new \DOMDocument('1.0', 'UTF-8');
639
        $domDocument->appendChild($this->toDomElement($domDocument, $namespaceURI));
640
        return $domDocument;
641
    }
642
643
    /**
644
     * Sets the filename of the schema file used for validation.
645
     *
646
     * @param string $schemaFile Filename of the schema for validation of the configuration node
647
     *
648
     * @return void
649
     */
650
    public function setSchemaFile($schemaFile)
651
    {
652
        $this->schemaFile = $schemaFile;
653
    }
654
655
    /**
656
     * Returns the filename of the schema file used for validation.
657
     *
658
     * @return string The filename of the schema file used for validation
659
     */
660
    public function getSchemaFile()
661
    {
662
        return $this->schemaFile;
663
    }
664
665
    /**
666
     * Recursively creates and returns a DOM element of this configuration node.
667
     *
668
     * @param \DOMDocument $domDocument  The DOM document necessary to create a \DOMElement instance
669
     * @param string       $namespaceURI The namespace URI to use
670
     *
671
     * @return \DOMElement The initialized DOM element
672
     */
673
    public function toDomElement(\DOMDocument $domDocument, $namespaceURI = null)
674
    {
675
        // if a namespace URI was given, create namespaced DOM element
676
        if ($namespaceURI) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $namespaceURI of type string|null is loosely compared to true; this is ambiguous if the string can be empty. You might want to explicitly use !== null instead.

In PHP, under loose comparison (like ==, or !=, or switch conditions), values of different types might be equal.

For string values, the empty string '' is a special case, in particular the following results might be unexpected:

''   == false // true
''   == null  // true
'ab' == false // false
'ab' == null  // false

// It is often better to use strict comparison
'' === false // false
'' === null  // false
Loading history...
677
            $domElement = $domDocument->createElementNS($namespaceURI, $this->getNodeName(), $this->getValue());
678
        } else {
679
            $domElement = $domDocument->createElement($this->getNodeName(), $this->getValue());
680
        }
681
682
        // append the element's attributes
683
        foreach ($this->getAllData() as $key => $value) {
684
            $domElement->setAttribute($key, $value);
685
        }
686
687
        // append the element's child nodes
688
        foreach ($this->getChildren() as $child) {
689
            $domElement->appendChild($child->toDomElement($domDocument));
690
        }
691
692
        // return the
693
        return $domElement;
694
    }
695
696
    /**
697
     * Validates the configuration node against the schema file.
698
     *
699
     * @throws \Exception Is thrown if the validation was not successful
700
     * @return \DOMDocument The validated DOM document
701
     * @see \AppserverIo\Configuration\Configuration::setSchemaFile()
702
     */
703
    public function validate()
704
    {
705
706
        // check if a schema file was specified and exists
707
        if ($this->getSchemaFile() == null) {
708
            throw new \Exception("Missing XSD schema file for validation");
709
        }
710
        if (file_exists($this->getSchemaFile()) === false) {
711
            throw new \Exception(sprintf("XSD schema file %s for validation not available", $this->getSchemaFile()));
712
        }
713
714
        // activate internal error handling, necessary to catch errors with libxml_get_errors()
715
        libxml_use_internal_errors(true);
716
717
        // recursively create a DOM document from the configuration node and validate it
718
        $domDocument = $this->toDomDocument();
719
        if ($domDocument->schemaValidate($this->getSchemaFile()) === false) {
720
            foreach (libxml_get_errors() as $error) {
721
                $message = "Found a schema validation error on line %s with code %s and message %s when validating configuration file %s";
722
723
                throw new \Exception(sprintf($message, $error->line, $error->code, $error->message, $error->file));
724
            }
725
        }
726
        return $domDocument;
727
    }
728
}
729