StreamClient::recv()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 6

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 10
c 0
b 0
f 0
cc 2
nc 2
nop 2
1
<?php
2
3
namespace Helix\Socket;
4
5
/**
6
 * Full duplex connection.
7
 */
8
class StreamClient extends AbstractClient {
9
10
    /**
11
     * `SOCK_STREAM`
12
     *
13
     * @return int
14
     */
15
    final public static function getType (): int {
16
        return SOCK_STREAM;
17
    }
18
19
    /**
20
     * Creates a pair of interconnected Unix instances that can be used for IPC.
21
     *
22
     * @see https://php.net/socket_create_pair
23
     *
24
     * @param array $extra Variadic constructor arguments.
25
     * @return static[] Two instances at indices `0` and `1`.
26
     * @throws SocketError
27
     */
28
    public static function newUnixPair (...$extra) {
29
        if (!@socket_create_pair(AF_UNIX, SOCK_STREAM, 0, $fd)) {
30
            throw new SocketError; // reliable errno
31
        }
32
        return [
33
            new static($fd[0], ...$extra),
0 ignored issues
show
Unused Code introduced by
The call to StreamClient::__construct() has too many arguments starting with $extra.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
34
            new static($fd[1], ...$extra)
0 ignored issues
show
Unused Code introduced by
The call to StreamClient::__construct() has too many arguments starting with $extra.

This check compares calls to functions or methods with their respective definitions. If the call has more arguments than are defined, it raises an issue.

If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress.

In this case you can add the @ignore PhpDoc annotation to the duplicate definition and it will be ignored.

Loading history...
35
        ];
36
    }
37
38
    /**
39
     * Reads the specified length from the peer (forced blocking).
40
     *
41
     * May return less than the desired length if the peer shut down writing or closed.
42
     *
43
     * @param int $length
44
     * @return string
45
     * @throws SocketError The partially read data is attached.
46
     */
47
    public function read (int $length): string {
48
        try {
49
            $data = '';
50
            do {
51
                $data .= $chunk = $this->awaitReadable()->recv($length);
52
                $length -= $chunkSize = strlen($chunk);
53
            } while ($chunkSize and $length);
54
            return $data;
55
        }
56
        catch (SocketError $e) {
57
            $e->setExtra($data);
58
            throw $e;
59
        }
60
    }
61
62
    /**
63
     * Receives up to a specified length from the peer.
64
     *
65
     * Returns an empty string if the peer shut down writing or closed.
66
     *
67
     * @see https://php.net/socket_recv
68
     *
69
     * @param int $maxLength
70
     * @param int $flags `MSG_*`
71
     * @return string
72
     * @throws SocketError
73
     */
74
    public function recv (int $maxLength, int $flags = 0): string {
75
        if (false === @socket_recv($this->resource, $data, $maxLength, $flags)) {
76
            throw new SocketError($this->resource, SOCKET_EINVAL);
77
        }
78
        return (string)$data; // cast needed, will be null if 0 bytes are read.
79
    }
80
81
    /**
82
     * All available data in the system buffer without blocking.
83
     *
84
     * @param int $flags `MSG_*`
85
     * @return string
86
     * @throws SocketError
87
     */
88
    public function recvAll (int $flags = 0): string {
89
        $flags = ($flags & ~MSG_WAITALL) | MSG_DONTWAIT;
90
        $length = $this->getOption(SO_RCVBUF);
91
        try {
92
            return $this->recv($length, $flags);
93
        }
94
        catch (SocketError $e) {
95
            if ($e->getCode() === SOCKET_EAGAIN) { // would block
96
                return '';
97
            }
98
            throw $e;
99
        }
100
    }
101
102
}
103