Completed
Push — master ( 0697b0...00bffc )
by Aydin
17s queued 15s
created

ResourceInputStream::__destruct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 2
Code Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
eloc 1
c 1
b 0
f 0
dl 0
loc 2
rs 10
cc 1
nc 1
nop 0
1
<?php
2
3
namespace PhpSchool\Terminal\IO;
4
5
use function is_resource;
6
use function get_resource_type;
7
use function stream_get_meta_data;
8
use function strpos;
9
10
/**
11
 * @author Aydin Hassan <[email protected]>
12
 */
13
class ResourceInputStream implements InputStream
14
{
15
    /**
16
     * @var resource
17
     */
18
    private $stream;
19
20
    /**
21
     * @var bool Original blocking state.
22
     */
23
    private $blocking;
24
25
    public function __construct($stream = STDIN)
26
    {
27
        if (!is_resource($stream) || get_resource_type($stream) !== 'stream') {
28
            throw new \InvalidArgumentException('Expected a valid stream');
29
        }
30
31
        $meta = stream_get_meta_data($stream);
32
        if (strpos($meta['mode'], 'r') === false && strpos($meta['mode'], '+') === false) {
33
            throw new \InvalidArgumentException('Expected a readable stream');
34
        }
35
36
        $meta = stream_get_meta_data($stream);
37
        $this->blocking = $meta['blocked'];
38
        $this->stream = $stream;
39
    }
40
41
    /**
42
     * Restore the blocking state.
43
     */
44
    public function __destruct() {
45
        stream_set_blocking($this->stream, $this->blocking);
46
    }
47
48
    public function read(int $numBytes, callable $callback) : void
49
    {
50
        $buffer = fread($this->stream, $numBytes);
51
        if (!empty($buffer)) {
52
            // Prevent blocking to handle pasted input.
53
            stream_set_blocking($this->stream, false);
54
        } else {
55
            // Re-enable blocking when input has been handled.
56
            stream_set_blocking($this->stream, true);
57
        }
58
59
        $callback($buffer);
60
    }
61
62
    /**
63
     * Whether the stream is connected to an interactive terminal
64
     */
65
    public function isInteractive() : bool
66
    {
67
        return posix_isatty($this->stream);
68
    }
69
}
70