ElementIterator::__get()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 0
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 1
crap 2
1
<?php
2
3
namespace Thruster\Component\XMLIterator;
4
5
/**
6
 * Class ElementIterator
7
 *
8
 * @package Thruster\Component\XMLIterator
9
 * @author  Aurimas Niekis <[email protected]>
10
 */
11
class ElementIterator extends XMLIterator
12
{
13
    /**
14
     * @var int
15
     */
16
    private $index;
0 ignored issues
show
Comprehensibility introduced by
Consider using a different property name as you override a private property of the parent class.
Loading history...
17
18
    /**
19
     * @var string
20
     */
21
    private $name;
22
23
    /**
24
     * @var bool
25
     */
26
    private $didRewind;
27
28
    /**
29
     * @param XMLReader   $reader
30
     * @param null|string $name element name, leave empty or use '*' for all elements
31
     */
32 8
    public function __construct(XMLReader $reader, $name = null)
33
    {
34 8
        parent::__construct($reader);
35
36 8
        $this->setName($name);
37 8
    }
38
39
    /**
40
     * @return void
41
     */
42 8
    public function rewind()
43
    {
44 8
        parent::rewind();
45
46 8
        $this->ensureCurrentElementState();
47 8
        $this->didRewind = true;
48 8
        $this->index     = 0;
49 8
    }
50
51
    /**
52
     * @return Node|null
53
     */
54 8
    public function current()
55
    {
56 8
        $this->didRewind || self::rewind();
57 8
        $this->ensureCurrentElementState();
58
59 8
        return self::valid() ? new Node($this->reader) : null;
60
    }
61
62 1
    public function key()
63
    {
64 1
        return $this->index;
65
    }
66
67 7
    public function next()
68
    {
69 7
        if (parent::valid()) {
0 ignored issues
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (valid() instead of next()). Are you sure this is correct? If so, you might want to change this to $this->valid().

This check looks for a call to a parent method whose name is different than the method from which it is called.

Consider the following code:

class Daddy
{
    protected function getFirstName()
    {
        return "Eidur";
    }

    protected function getSurName()
    {
        return "Gudjohnsen";
    }
}

class Son
{
    public function getFirstName()
    {
        return parent::getSurname();
    }
}

The getFirstName() method in the Son calls the wrong method in the parent class.

Loading history...
70 7
            $this->index++;
71
        }
72 7
        parent::next();
73 7
        $this->ensureCurrentElementState();
74 7
    }
75
76
    /**
77
     * @return array
78
     */
79 1
    public function toArray()
80
    {
81 1
        $array = [];
82 1
        $this->didRewind || $this->rewind();
83 1
        if (!$this->valid()) {
84
            return [];
85
        }
86 1
        $this->ensureCurrentElementState();
87 1
        while ($this->valid()) {
88 1
            $element = new Node($this->reader);
89 1
            if ($this->reader->hasValue) {
90
                $string = $this->reader->value;
91
            } else {
92 1
                $string = $element->readString();
93
            }
94 1
            if ($this->name) {
95
                $array[] = $string;
96
            } else {
97 1
                $array[$element->name] = $string;
0 ignored issues
show
Documentation introduced by
The property $name is declared private in Thruster\Component\XMLIterator\Node. Since you implemented __get(), maybe consider adding a @property or @property-read annotation. This makes it easier for IDEs to provide auto-completion.

Since your code implements the magic setter _set, this function will be called for any write access on an undefined variable. You can add the @property annotation to your class or interface to document the existence of this variable.

<?php

/**
 * @property int $x
 * @property int $y
 * @property string $text
 */
class MyLabel
{
    private $properties;

    private $allowedProperties = array('x', 'y', 'text');

    public function __get($name)
    {
        if (isset($properties[$name]) && in_array($name, $this->allowedProperties)) {
            return $properties[$name];
        } else {
            return null;
        }
    }

    public function __set($name, $value)
    {
        if (in_array($name, $this->allowedProperties)) {
            $properties[$name] = $value;
        } else {
            throw new \LogicException("Property $name is not defined.");
        }
    }

}

Since the property has write access only, you can use the @property-write annotation instead.

Of course, you may also just have mistyped another name, in which case you should fix the error.

See also the PhpDoc documentation for @property.

Loading history...
98
            }
99 1
            $this->moveToNextElementByName($this->name);
100
        }
101
102 1
        return $array;
103
    }
104
105
    /**
106
     * @return string
107
     */
108 2
    public function __toString()
109
    {
110 2
        return $this->readString();
0 ignored issues
show
Documentation Bug introduced by
The method readString does not exist on object<Thruster\Componen...erator\ElementIterator>? Since you implemented __call, maybe consider adding a @method annotation.

If you implement __call and you know which methods are available, you can improve IDE auto-completion and static analysis by adding a @method annotation to the class.

This is often the case, when __call is implemented by a parent class and only the child class knows which methods exist:

class ParentClass {
    private $data = array();

    public function __call($method, array $args) {
        if (0 === strpos($method, 'get')) {
            return $this->data[strtolower(substr($method, 3))];
        }

        throw new \LogicException(sprintf('Unsupported method: %s', $method));
    }
}

/**
 * If this class knows which fields exist, you can specify the methods here:
 *
 * @method string getName()
 */
class SomeClass extends ParentClass { }
Loading history...
111
    }
112
113
    /**
114
     * decorate method calls
115
     *
116
     * @param string $name
117
     * @param array  $args
118
     *
119
     * @return mixed
120
     */
121 2
    public function __call($name, $args)
122
    {
123 2
        return call_user_func_array([$this->current(), $name], $args);
124
    }
125
126
    /**
127
     * decorate property get
128
     *
129
     * @param string $name
130
     *
131
     * @return string
132
     */
133
    public function __get($name)
134
    {
135
        return $this->current()->$name;
136
    }
137
138
    /**
139
     * @param null|string $name
140
     */
141 8
    public function setName($name = null)
142
    {
143 8
        $this->name = '*' === $name ? null : $name;
144 8
    }
145
146
    /**
147
     * take care the underlying XMLReader is at an element with a fitting name (if $this is looking for a name)
148
     */
149 8
    private function ensureCurrentElementState()
150
    {
151 8
        if ($this->reader->nodeType !== XMLReader::ELEMENT) {
152 7
            $this->moveToNextElementByName($this->name);
153 8
        } elseif ($this->name && $this->name !== $this->reader->name) {
154 2
            $this->moveToNextElementByName($this->name);
155
        }
156 8
    }
157
}
158