FnStream::detach()   A
last analyzed

Complexity

Conditions 1
Paths 1

Size

Total Lines 3
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 1
c 1
b 0
f 0
nc 1
nop 0
dl 0
loc 3
rs 10
1
<?php declare(strict_types=1);
2
3
namespace One\Http;
4
5
use Psr\Http\Message\StreamInterface;
6
7
/**
8
 * @property string $_fn___toString Contains function name as value
9
 * @property string $_fn_close Contains function name as value
10
 * @property string $_fn_detach Contains function name as value
11
 * @property string $_fn_rewind Contains function name as value
12
 * @property string $_fn_getSize Contains function name as value
13
 * @property string $_fn_tell Contains function name as value
14
 * @property string $_fn_eof Contains function name as value
15
 * @property string $_fn_isSeekable Contains function name as value
16
 * @property string $_fn_seek Contains function name as value
17
 * @property string $_fn_isWritable Contains function name as value
18
 * @property string $_fn_write Contains function name as value
19
 * @property string $_fn_isReadable Contains function name as value
20
 * @property string $_fn_read Contains function name as value
21
 * @property string $_fn_getContents Contains function name as value
22
 * @property string $_fn_getMetadata Contains function name as value
23
 * @property string[] $slots An array that store list of function name
24
 */
25
class FnStream implements StreamInterface
26
{
27
    /**
28
     * Slots
29
     * @var array<string>
30
     */
31
    private static $slots = ['__toString', 'close', 'detach', 'rewind',
32
        'getSize', 'tell', 'eof', 'isSeekable', 'seek', 'isWritable', 'write',
33
        'isReadable', 'read', 'getContents', 'getMetadata', ];
34
35
    /**
36
     * @param array $methods Hash of method name to a callable.
37
     */
38
    public function __construct(array $methods)
39
    {
40
        // Create the functions on the class
41
        foreach ($methods as $name => $fn) {
42
            $this->{'_fn_' . $name} = $fn;
43
        }
44
    }
45
46
    /**
47
     * The close method is called on the underlying stream only if possible.
48
     */
49
    public function __destruct()
50
    {
51
        if (isset($this->_fn_close)) {
52
            call_user_func($this->_fn_close);
53
        }
54
    }
55
56
    /**
57
     * Lazily determine which methods are not implemented.
58
     * @throws \BadMethodCallException
59
     */
60
    public function __get(string $name): void
61
    {
62
        throw new \BadMethodCallException(str_replace('_fn_', '', $name)
63
            . '() is not implemented in the FnStream');
64
    }
65
66
    /**
67
     * An unserialize would allow the __destruct to run when the unserialized value goes out of scope.
68
     * @throws \LogicException
69
     */
70
    public function __wakeup(): void
71
    {
72
        throw new \LogicException('FnStream should never be unserialized');
73
    }
74
75
    /**
76
     * @inheritDoc
77
     */
78
    public function __toString()
79
    {
80
        return call_user_func($this->_fn___toString);
81
    }
82
83
    /**
84
     * Adds custom functionality to an underlying stream by intercepting
85
     * specific method calls.
86
     *
87
     * @param StreamInterface $stream  Stream to decorate
88
     * @param array           $methods Hash of method name to a closure
89
     */
90
    public static function decorate(StreamInterface $stream, array $methods): self
91
    {
92
        // If any of the required methods were not provided, then simply
93
        // proxy to the decorated stream.
94
        foreach (array_diff(self::$slots, array_keys($methods)) as $diff) {
95
            $methods[$diff] = [$stream, $diff];
96
        }
97
        return new self($methods);
98
    }
99
100
    /**
101
     * @inheritDoc
102
     */
103
    public function close()
104
    {
105
        return call_user_func($this->_fn_close);
106
    }
107
108
    /**
109
     * @inheritDoc
110
     */
111
    public function detach()
112
    {
113
        return call_user_func($this->_fn_detach);
114
    }
115
116
    /**
117
     * @inheritDoc
118
     */
119
    public function getSize()
120
    {
121
        return call_user_func($this->_fn_getSize);
122
    }
123
124
    /**
125
     * @inheritDoc
126
     */
127
    public function tell()
128
    {
129
        return call_user_func($this->_fn_tell);
130
    }
131
132
    /**
133
     * @inheritDoc
134
     */
135
    public function eof()
136
    {
137
        return call_user_func($this->_fn_eof);
138
    }
139
140
    /**
141
     * @inheritDoc
142
     */
143
    public function isSeekable()
144
    {
145
        return call_user_func($this->_fn_isSeekable);
146
    }
147
148
    /**
149
     * @inheritDoc
150
     */
151
    public function rewind(): void
152
    {
153
        call_user_func($this->_fn_rewind);
154
    }
155
156
    /**
157
     * @inheritDoc
158
     */
159
    public function seek($offset, $whence = SEEK_SET): void
160
    {
161
        call_user_func($this->_fn_seek, $offset, $whence);
162
    }
163
164
    /**
165
     * @inheritDoc
166
     */
167
    public function isWritable()
168
    {
169
        return call_user_func($this->_fn_isWritable);
170
    }
171
172
    /**
173
     * @inheritDoc
174
     */
175
    public function write($string)
176
    {
177
        return call_user_func($this->_fn_write, $string);
178
    }
179
180
    /**
181
     * @inheritDoc
182
     */
183
    public function isReadable()
184
    {
185
        return call_user_func($this->_fn_isReadable);
186
    }
187
188
    /**
189
     * @inheritDoc
190
     */
191
    public function read($length)
192
    {
193
        return call_user_func($this->_fn_read, $length);
194
    }
195
196
    /**
197
     * @inheritDoc
198
     */
199
    public function getContents()
200
    {
201
        return call_user_func($this->_fn_getContents);
202
    }
203
204
    /**
205
     * @inheritDoc
206
     */
207
    public function getMetadata($key = null)
208
    {
209
        return call_user_func($this->_fn_getMetadata, $key);
210
    }
211
}
212