Completed
Push — master ( 8a2252...d25bda )
by
unknown
01:43
created

CallbackStream   A

Complexity

Total Complexity 19

Size/Duplication

Total Lines 201
Duplicated Lines 0 %

Coupling/Cohesion

Components 1
Dependencies 0

Importance

Changes 0
Metric Value
wmc 19
lcom 1
cbo 0
dl 0
loc 201
rs 10
c 0
b 0
f 0

17 Methods

Rating   Name   Duplication   Size   Complexity  
A __construct() 0 4 1
A __toString() 0 4 1
A output() 0 12 2
A close() 0 3 1
A detach() 0 7 1
A getSize() 0 3 1
A tell() 0 4 1
A eof() 0 4 1
A isSeekable() 0 4 1
A seek() 0 4 1
A rewind() 0 4 1
A isWritable() 0 4 1
A write() 0 4 1
A isReadable() 0 4 1
A read() 0 4 1
A getContents() 0 4 1
A getMetadata() 0 8 2
1
<?php
2
3
namespace Charcoal\App\Helper;
4
5
use Psr\Http\Message\StreamInterface;
6
7
/**
8
 * Callback-based stream implementation.
9
 * Wraps a callback, and invokes it in order to stream it.
10
 * Only one invocation is allowed; multiple invocations will return an empty
11
 * string for the second and subsequent calls.
12
 */
13
class CallbackStream implements StreamInterface
14
{
15
    /**
16
     * @var callable
17
     */
18
    private $callback;
19
20
    /**
21
     *
22
     * Whether or not the callback has been previously invoked.
23
     * @var boolean
24
     */
25
    private $called = false;
26
27
    /**
28
     * CallbackStream constructor.
29
     * @param callable $callback The callback stream.
30
     */
31
    public function __construct(callable $callback)
32
    {
33
        $this->callback = $callback;
34
    }
35
36
    /**
37
     *
38
     * @return string
39
     */
40
    public function __toString()
41
    {
42
        return $this->output();
43
    }
44
45
    /**
46
     *
47
     * Execute the callback with output buffering.
48
     *
49
     * @return null|string Null on second and subsequent calls.
50
     */
51
    public function output()
52
    {
53
        if ($this->called) {
54
            return;
55
        }
56
57
        $this->called = true;
58
59
        call_user_func($this->callback);
60
61
        return;
62
    }
63
64
    /**
65
     *
66
     * @return void
67
     */
68
    public function close()
69
    {
70
    }
71
72
    /**
73
     *
74
     * @return null|callable
75
     */
76
    public function detach()
77
    {
78
        $callback       = $this->callback;
79
        $this->callback = null;
80
81
        return $callback;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $callback; (callable) is incompatible with the return type declared by the interface Psr\Http\Message\StreamInterface::detach of type resource|null.

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...
82
    }
83
84
    /**
85
     *
86
     * @return integer|null Returns the size in bytes if known, or null if unknown.
87
     */
88
    public function getSize()
89
    {
90
    }
91
92
    /**
93
     *
94
     * @return integer|boolean Position of the file pointer or false on error.
95
     */
96
    public function tell()
97
    {
98
        return 0;
99
    }
100
101
    /**
102
     *
103
     * @return boolean
104
     */
105
    public function eof()
106
    {
107
        return $this->called;
108
    }
109
110
    /**
111
     *
112
     * @return boolean
113
     */
114
    public function isSeekable()
115
    {
116
        return false;
117
    }
118
119
    /**
120
     *
121
     * @link http://www.php.net/manual/en/function.fseek.php 1
122
     * @param integer $offset Stream offset
123
     * @param integer $whence Specifies how the cursor position will be calculated
124
     *                    based on the seek offset. Valid values are identical to the built-in
125
     *                    PHP $whence values for `fseek()`.  SEEK_SET: Set position equal to
126
     *                    offset bytes SEEK_CUR: Set position to current location plus offset
127
     *                    SEEK_END: Set position to end-of-stream plus offset.
128
     * @return boolean Returns TRUE on success or FALSE on failure.
129
     */
130
    public function seek($offset, $whence = SEEK_SET)
131
    {
132
        return false;
133
    }
134
135
    /**
136
     *
137
     * @see  seek()
138
     * @link http://www.php.net/manual/en/function.fseek.php 1
139
     * @return boolean Returns TRUE on success or FALSE on failure.
140
     */
141
    public function rewind()
142
    {
143
        return false;
144
    }
145
146
    /**
147
     *
148
     * @return boolean
149
     */
150
    public function isWritable()
151
    {
152
        return false;
153
    }
154
155
    /**
156
     *
157
     * @param string $string The string that is to be written.
158
     * @return integer|boolean Returns the number of bytes written to the stream on
159
     *                       success or FALSE on failure.
160
     */
161
    public function write($string)
162
    {
163
        return false;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return false; (false) is incompatible with the return type declared by the interface Psr\Http\Message\StreamInterface::write of type integer.

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...
164
    }
165
166
    /**
167
     *
168
     * @return boolean
169
     */
170
    public function isReadable()
171
    {
172
        return true;
173
    }
174
175
    /**
176
     *
177
     * @param integer $length Read up to $length bytes from the object and return
178
     *                    them. Fewer than $length bytes may be returned if underlying stream
179
     *                    call returns fewer bytes.
180
     * @return string|false Returns the data read from the stream, false if
181
     *                    unable to read or if an error occurs.
182
     */
183
    public function read($length)
184
    {
185
        return $this->output();
186
    }
187
188
    /**
189
     *
190
     * @return string
191
     */
192
    public function getContents()
193
    {
194
        return $this->output();
195
    }
196
197
    /**
198
     *
199
     * @link http://php.net/manual/en/function.stream-get-meta-data.php 2
200
     * @param string $key Specific metadata to retrieve.
201
     * @return array|mixed|null Returns an associative array if no key is
202
     *                    provided. Returns a specific key value if a key is provided and the
203
     *                    value is found, or null if the key is not found.
204
     */
205
    public function getMetadata($key = null)
206
    {
207
        if ($key === null) {
208
            return [];
209
        }
210
211
        return null;
212
    }
213
}
214