Completed
Push — master ( c0420c...edd451 )
by thomas
39:10 queued 24:08
created

Buffer::getInternalSize()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 1 Features 0
Metric Value
c 1
b 1
f 0
dl 0
loc 4
rs 10
cc 1
eloc 2
nc 1
nop 0
1
<?php
2
3
namespace BitWasp\Buffertools;
4
5
use Mdanter\Ecc\EccFactory;
6
use Mdanter\Ecc\Math\GmpMathInterface;
7
8
class Buffer implements BufferInterface
9
{
10
    /**
11
     * @var int
12
     */
13
    protected $size;
14
15
    /**
16
     * @var string
17
     */
18
    protected $buffer;
19
20
    /**
21
     * @var GmpMathInterface
22
     */
23
    protected $math;
24
25
    /**
26
     * @param string               $byteString
27
     * @param null|integer         $byteSize
28
     * @param GmpMathInterface     $math
29
     * @throws \Exception
30
     */
31
    public function __construct($byteString = '', $byteSize = null, GmpMathInterface $math = null)
32
    {
33
        $this->math = $math ?: EccFactory::getAdapter();
34
        if ($byteSize !== null) {
35
            // Check the integer doesn't overflow its supposed size
36
            if (strlen($byteString) > $byteSize) {
37
                throw new \Exception('Byte string exceeds maximum size');
38
            }
39
        } else {
40
            $byteSize = strlen($byteString);
41
        }
42
43
        $this->size   = $byteSize;
44
        $this->buffer = $byteString;
45
    }
46
47
    /**
48
     * Create a new buffer from a hex string
49
     *
50
     * @param string $hexString
51
     * @param integer $byteSize
52
     * @param GmpMathInterface $math
53
     * @return Buffer
54
     * @throws \Exception
55
     */
56
    public static function hex($hexString = '', $byteSize = null, GmpMathInterface $math = null)
57
    {
58
        if (strlen($hexString) > 0 && !ctype_xdigit($hexString)) {
59
            throw new \InvalidArgumentException('BufferHex: non-hex character passed: ' . $hexString);
60
        }
61
62
        $math = $math ?: EccFactory::getAdapter();
63
        $binary = pack("H*", $hexString);
64
        return new self($binary, $byteSize, $math);
65
    }
66
67
    /**
68
     * @param int|string $integer
69
     * @param null|int $byteSize
70
     * @param GmpMathInterface|null $math
71
     * @return Buffer
72
     */
73
    public static function int($integer, $byteSize = null, GmpMathInterface $math = null)
74
    {
75
        $math = $math ?: EccFactory::getAdapter();
76
        $binary = pack("H*", $math->decHex($integer));
77
        return new self($binary, $byteSize, $math);
78
    }
79
80
    /**
81
     * @param integer      $start
82
     * @param integer|null $end
83
     * @return Buffer
84
     * @throws \Exception
85
     */
86
    public function slice($start, $end = null)
87
    {
88
        if ($start > $this->getSize()) {
89
            throw new \Exception('Start exceeds buffer length');
90
        }
91
92
        if ($end === null) {
93
            return new self(substr($this->getBinary(), $start));
94
        }
95
96
        if ($end > $this->getSize()) {
97
            throw new \Exception('Length exceeds buffer length');
98
        }
99
100
        $string = substr($this->getBinary(), $start, $end);
101
        $length = strlen($string);
102
        return new self($string, $length, $this->math);
103
    }
104
105
    /**
106
     * Get the size of the buffer to be returned
107
     *
108
     * @return int
109
     */
110
    public function getSize()
111
    {
112
        return $this->size;
113
    }
114
115
    /**
116
     * Get the size of the value stored in the buffer
117
     *
118
     * @return int
119
     */
120
    public function getInternalSize()
121
    {
122
        return strlen($this->buffer);
123
    }
124
125
    /**
126
     * @return string
127
     */
128
    public function getBinary()
129
    {
130
        // if a size is specified we'll make sure the value returned is that size
131
        if ($this->size !== null) {
132
            if (strlen($this->buffer) < $this->size) {
133
                return str_pad($this->buffer, $this->size, chr(0), STR_PAD_LEFT);
134
            } elseif (strlen($this->buffer) > $this->size) {
135
                return substr($this->buffer, 0, $this->size);
136
            }
137
        }
138
139
        return $this->buffer;
140
    }
141
142
    /**
143
     * @return string
144
     */
145
    public function getHex()
146
    {
147
        return bin2hex($this->getBinary());
148
    }
149
150
    /**
151
     * @return \GMP
152
     */
153
    public function getGmp()
154
    {
155
        $gmp = gmp_init($this->getHex(), 16);
156
        return $gmp;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $gmp; (resource) is incompatible with the return type declared by the interface BitWasp\Buffertools\BufferInterface::getGmp of type GMP.

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...
157
    }
158
159
    /**
160
     * @return int|string
161
     */
162
    public function getInt()
163
    {
164
        return gmp_strval($this->getGmp(), 10);
165
    }
166
167
    /**
168
     * @return Buffer
169
     */
170
    public function flip()
171
    {
172
        return Buffertools::flipBytes($this);
0 ignored issues
show
Bug Compatibility introduced by
The expression \BitWasp\Buffertools\Buf...ools::flipBytes($this); of type BitWasp\Buffertools\Buffer|string adds the type string to the return on line 172 which is incompatible with the return type declared by the interface BitWasp\Buffertools\BufferInterface::flip of type BitWasp\Buffertools\Buffer.
Loading history...
173
    }
174
175
    /**
176
     * @param BufferInterface $other
177
     * @return bool
178
     */
179
    public function equals(BufferInterface $other)
180
    {
181
        return ($other->getSize() === $this->getSize()
182
             && $other->getBinary() === $this->getBinary());
183
    }
184
}
185