Passed
Push — master ( b4e552...a91d54 )
by y
03:05
created

StreamClient   A

Complexity

Total Complexity 10

Size/Duplication

Total Lines 81
Duplicated Lines 0 %

Importance

Changes 18
Bugs 1 Features 3
Metric Value
eloc 25
c 18
b 1
f 3
dl 0
loc 81
rs 10
wmc 10

4 Methods

Rating   Name   Duplication   Size   Complexity  
A read() 0 16 4
A getType() 0 2 1
A newUnixPair() 0 7 2
A recv() 0 10 3
1
<?php
2
3
namespace Helix\Socket;
4
5
/**
6
 * Full duplex connection.
7
 */
8
class StreamClient extends AbstractClient {
9
10
    /**
11
     * **Variadic.**
12
     * Creates a pair of interconnected Unix instances that can be used for IPC.
13
     *
14
     * @link https://php.net/socket_create_pair
15
     *
16
     * @param array $extra Variadic constructor arguments.
17
     * @return static[] Two instances at indices `0` and `1`.
18
     * @throws Error
19
     */
20
    public static function newUnixPair (...$extra) {
21
        if (!@socket_create_pair(AF_UNIX, SOCK_STREAM, 0, $fd)) {
22
            throw new Error; // reliable errno
23
        }
24
        return [
25
            new static(...array_merge([$fd[0]], $extra)),
0 ignored issues
show
Bug introduced by
array_merge(array($fd[0]), $extra) is expanded, but the parameter $resource of Helix\Socket\StreamClient::__construct() does not expect variable arguments. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

25
            new static(/** @scrutinizer ignore-type */ ...array_merge([$fd[0]], $extra)),
Loading history...
26
            new static(...array_merge([$fd[1]], $extra))
27
        ];
28
    }
29
30
    /**
31
     * `SOCK_STREAM`
32
     *
33
     * @return int
34
     */
35
    final public static function getType () {
36
        return SOCK_STREAM;
37
    }
38
39
    /**
40
     * Reads the specified length in a blocking manner.
41
     * May return less than the desired length if the peer shut down writing.
42
     *
43
     * @see onTimeout()
44
     *
45
     * @param int $length
46
     * @return string
47
     * @throws Error The error's extra data is set to what was partially read.
48
     */
49
    public function read ($length) {
50
        $data = '';
51
        while ($length > 0) {
52
            try {
53
                $data .= $chunk = $this->await(self::CH_READ)->recv($length);
54
                $length -= strlen($chunk);
55
                if ($chunk === '') {
56
                    return $data;
57
                }
58
            }
59
            catch (Error $error) {
60
                $error->setExtra($data);
61
                throw $error;
62
            }
63
        }
64
        return $data;
65
    }
66
67
    /**
68
     * Receives data from the peer.
69
     *
70
     * @link https://php.net/socket_recv
71
     *
72
     * @see onTimeout()
73
     *
74
     * @param int $length Maximum amount of bytes to receive.
75
     * @param int $flags `MSG_*`
76
     * @throws Error
77
     * @return string
78
     */
79
    public function recv ($length, $flags = 0) {
80
        $count = @socket_recv($this->resource, $data, $length, $flags);
81
        if ($count === false) {
82
            $error = new Error($this->resource, SOCKET_EINVAL);
83
            if ($error->getCode() === SOCKET_ETIMEDOUT) {
84
                $this->onTimeout();
85
            }
86
            throw $error;
87
        }
88
        return (string)$data; // cast needed, will be null if 0 bytes are read.
89
    }
90
91
}
92