Completed
Push — master ( 838d3a...3b658f )
by thomas
22:41 queued 01:10
created

Stack::__construct()   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 1
Bugs 0 Features 0
Metric Value
c 1
b 0
f 0
dl 0
loc 4
ccs 3
cts 3
cp 1
rs 10
cc 1
eloc 2
nc 1
nop 0
crap 1
1
<?php
2
3
namespace BitWasp\Bitcoin\Script\Interpreter;
4
5
use BitWasp\Buffertools\Buffer;
6
7
class Stack extends \SplDoublyLinkedList implements StackInterface
8
{
9 834
    public function __construct()
10
    {
11 834
        $this->setIteratorMode(\SplDoublyLinkedList::IT_MODE_FIFO | \SplDoublyLinkedList::IT_MODE_FIFO);
12 834
    }
13
14
    /**
15
     * @param mixed $value
16
     * @throws \InvalidArgumentException
17
     */
18 54
    private function typeCheck($value)
19
    {
20 54
        if (!$value instanceof Buffer) {
21
            throw new \InvalidArgumentException('Value was not of type Buffer');
22
        }
23 54
    }
24
25
    /**
26
     * @see \ArrayAccess::offsetGet()
27
     * @param int $offset
28
     * @return \BitWasp\Buffertools\Buffer
29
     */
30 486
    public function offsetGet($offset)
31
    {
32 486
        $offset = count($this) + $offset;
33 486
        return parent::offsetGet($offset);
34
    }
35
36
    /**
37
     * @see \ArrayAccess::offsetSet()
38
     * @param int $offset
39
     * @param Buffer $value
40
     * @throws \InvalidArgumentException
41
     */
42 36
    public function offsetSet($offset, $value)
43
    {
44 36
        $this->typeCheck($value);
45 36
        $offset = count($this) + $offset;
46 36
        parent::offsetSet($offset, $value);
47 36
    }
48
49
    /**
50
     * @see \ArrayAccess::offsetExists()
51
     * @param int $offset
52
     * @return bool
53
     */
54 6
    public function offsetExists($offset)
55
    {
56 6
        $offset = count($this) + $offset;
57 6
        return parent::offsetExists($offset);
58
    }
59
60
    /**
61
     * @see \ArrayAccess::offsetUnset()
62
     * @param int $offset
63
     */
64 36
    public function offsetUnset($offset)
65
    {
66 36
        $offset = count($this) + $offset;
67 36
        parent::offsetUnset($offset);
68 30
    }
69
70
    /**
71
     * @param int $first
72
     * @param int $second
73
     */
74 24
    public function swap($first, $second)
75
    {
76 24
        $val1 = $this->offsetGet($first);
77 24
        $val2 = $this->offsetGet($second);
78 24
        $this->offsetSet($second, $val1);
79 24
        $this->offsetSet($first, $val2);
80 24
    }
81
82
    /**
83
     * @param int $index
84
     * @param Buffer $value
85
     */
86 18
    public function add($index, $value)
87
    {
88 18
        $this->typeCheck($value);
89
90 18
        if (getenv('HHVM_VERSION') || version_compare(phpversion(), '5.5.0', 'lt')) {
91 6
            if ($index == $this->count()) {
92 2
                $this->push($value);
93 2
            } else {
94 4
                $size = count($this);
95 4
                $temp = [];
96 4
                for ($i = $size; $i > $index; $i--) {
97 4
                    array_unshift($temp, $this->pop());
98 4
                }
99
100 2
                $this->push($value);
101 2
                foreach ($temp as $value) {
102 2
                    $this->push($value);
103 2
                }
104
            }
105
106 4
        } else {
107 12
            parent::add($index, $value);
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class SplDoublyLinkedList as the method add() does only exist in the following sub-classes of SplDoublyLinkedList: BitWasp\Bitcoin\Script\Interpreter\Stack. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
108
        }
109 12
    }
110
111
    /**
112
     * @return int
113
     */
114 684
    public function end()
115
    {
116 684
        $count = count($this);
117 684
        if ($count === 0) {
118 684
            return 0;
119
        }
120
121 12
        return $count - 1;
122
    }
123
}
124