Completed
Push — master ( 96b297...3db3a5 )
by Thomas
02:30
created

XMLReader::getAttribute()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 2

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 1
dl 0
loc 8
ccs 5
cts 5
cp 1
crap 2
rs 9.4285
c 0
b 0
f 0
1
<?php
2
3
namespace FluentDOM {
4
5
  use DOMNode;
6
7
  class XMLReader extends \XMLReader {
8
9
    /**
10
     * @var Namespaces
11
     */
12
    private $_namespaces;
13
14
    /**
15
     * Store last used document to avoid early GC
16
     * @var Document
17
     */
18
    private $_document;
19
20 7
    public function __construct() {
21 7
      $this->_namespaces = new Namespaces();
22 7
    }
23
24
    /**
25
     * register a namespace prefix for the xml reader, it will be used in
26
     * next() and other methods with a tag name argument
27
     *
28
     * @param string $prefix
29
     * @param string $namespace
30
     * @throws \LogicException
31
     */
32 4
    public function registerNamespace($prefix, $namespace) {
33 4
      $this->_namespaces[$prefix] = $namespace;
34 4
    }
35
36
    /**
37
     * Positions cursor on the next node skipping all subtrees. If $name contains
38
     * a namespace prefix it will be resolved using the registered namespaces.
39
     *
40
     * @param null|string $name The name of the next node to move to.
41
     * @return bool
42
     */
43 2
    public function next($name = NULL) {
44 2
      if (isset($name)) {
45 2
        list($prefix, $localName) = QualifiedName::split($name);
46 2
        $namespaceUri = $this->_namespaces->resolveNamespace($prefix);
0 ignored issues
show
Security Bug introduced by
It seems like $prefix defined by \FluentDOM\QualifiedName::split($name) on line 45 can also be of type false; however, FluentDOM\Namespaces::resolveNamespace() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
47 2
        $ignoreNamespace = ($prefix === FALSE && $namespaceUri === '');
48 2
      } else {
49
        $ignoreNamespace = TRUE;
50
        $namespaceUri = '';
51
      }
52 2
      if ($ignoreNamespace) {
53 1
        return parent::next($name);
54
      } else {
55 1
        while (parent::next($localName)) {
0 ignored issues
show
Bug introduced by
The variable $localName does not seem to be defined for all execution paths leading up to this point.

If you define a variable conditionally, it can happen that it is not defined for all execution paths.

Let’s take a look at an example:

function myFunction($a) {
    switch ($a) {
        case 'foo':
            $x = 1;
            break;

        case 'bar':
            $x = 2;
            break;
    }

    // $x is potentially undefined here.
    echo $x;
}

In the above example, the variable $x is defined if you pass “foo” or “bar” as argument for $a. However, since the switch statement has no default case statement, if you pass any other value, the variable $x would be undefined.

Available Fixes

  1. Check for existence of the variable explicitly:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        if (isset($x)) { // Make sure it's always set.
            echo $x;
        }
    }
    
  2. Define a default value for the variable:

    function myFunction($a) {
        $x = ''; // Set a default which gets overridden for certain paths.
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
        }
    
        echo $x;
    }
    
  3. Add a value for the missing path:

    function myFunction($a) {
        switch ($a) {
            case 'foo':
                $x = 1;
                break;
    
            case 'bar':
                $x = 2;
                break;
    
            // We add support for the missing case.
            default:
                $x = '';
                break;
        }
    
        echo $x;
    }
    
Loading history...
56 1
          if ($this->namespaceURI === $namespaceUri) {
57 1
            return TRUE;
58
          }
59 1
        }
60 1
        return FALSE;
61
      }
62
    }
63
64
    /**
65
     * Move to next node in document, including subtrees. If $name contains
66
     * a namespace prefix it will be resolved using the registered namespaces.
67
     *
68
     * @param null|string $name The name of the next node to move to.
69
     * @return bool
70
     */
71 7
    public function read($name = NULL) {
72 7
      if (isset($name)) {
73 4
        list($prefix, $localName) = QualifiedName::split($name);
74 4
        $namespaceUri = $this->_namespaces->resolveNamespace($prefix);
0 ignored issues
show
Security Bug introduced by
It seems like $prefix defined by \FluentDOM\QualifiedName::split($name) on line 73 can also be of type false; however, FluentDOM\Namespaces::resolveNamespace() does only seem to accept string, did you maybe forget to handle an error condition?

This check looks for type mismatches where the missing type is false. This is usually indicative of an error condtion.

Consider the follow example

<?php

function getDate($date)
{
    if ($date !== null) {
        return new DateTime($date);
    }

    return false;
}

This function either returns a new DateTime object or false, if there was an error. This is a typical pattern in PHP programming to show that an error has occurred without raising an exception. The calling code should check for this returned false before passing on the value to another function or method that may not be able to handle a false.

Loading history...
75 4
        $ignoreNamespace = ($prefix === FALSE && $namespaceUri === '');
76 4
        while (parent::read()) {
77
          if (
78 4
            $this->nodeType === XML_ELEMENT_NODE &&
79 4
            $this->localName === $localName &&
80
            (
81
              $ignoreNamespace ||
82 2
              $this->namespaceURI === $namespaceUri
83 2
            )
84 4
          ) {
85 4
            return TRUE;
86
          }
87 4
        }
88 2
        return FALSE;
89
      } else {
90 3
        return parent::read();
91
      }
92
    }
93
94
    /**
95
     * Return attribute by name, resolve namespace prefix if included.
96
     *
97
     * @param string $name
98
     * @return NULL|string
99
     */
100 5
    public function getAttribute($name) {
101 5
      list($prefix, $localName) = QualifiedName::split($name);
102 5
      if (empty($prefix)) {
103 4
        return parent::getAttribute($name);
104
      } else {
105 1
        return parent::getAttributeNs($localName, $this->_namespaces->resolveNamespace($prefix));
1 ignored issue
show
Comprehensibility Bug introduced by
It seems like you call parent on a different method (getAttributeNs() instead of getAttribute()). Are you sure this is correct? If so, you might want to change this to $this->getAttributeNs().

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...
106
      }
107
    }
108
109 2
    public function expand(DOMNode $baseNode = NULL) {
110 2
      if (isset($baseNode)) {
111 1
        return parent::expand($baseNode);
112
      } else {
113 1
        $this->_document = $document = new Document();
114 1
        $document->namespaces($this->_namespaces);
115 1
        return parent::expand($document);
116
      }
117
    }
118
  }
119
}