1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
namespace App\Component\Console; |
6
|
|
|
|
7
|
|
|
class Input |
8
|
|
|
{ |
9
|
|
|
|
10
|
|
|
const STREAM_STDIN = 'php://stdin'; |
11
|
|
|
const STREAM_MEMORY = 'php://memory'; |
12
|
|
|
const STREAM_TEMP = 'php://temp'; |
13
|
|
|
const STREAM_MODE_READ = 'r'; |
14
|
|
|
const STREAM_MODE_APPEND = 'r+'; |
15
|
|
|
const STREAM_MODE_WRITE = 'w'; |
16
|
|
|
const STREAM_MODE_WRITE_APPEND = 'w+'; |
17
|
|
|
const DEBUGER = 'phpdbg'; |
18
|
|
|
|
19
|
|
|
/** |
20
|
|
|
* streamName |
21
|
|
|
* |
22
|
|
|
* @var string |
23
|
|
|
*/ |
24
|
|
|
protected $streamName; |
25
|
|
|
|
26
|
|
|
/** |
27
|
|
|
* streamMode |
28
|
|
|
* |
29
|
|
|
* @var string |
30
|
|
|
*/ |
31
|
|
|
protected $streamMode; |
32
|
|
|
|
33
|
|
|
/** |
34
|
|
|
* $streamHandler |
35
|
|
|
* |
36
|
|
|
* @var resource |
37
|
|
|
*/ |
38
|
|
|
protected $streamHandler; |
39
|
|
|
|
40
|
|
|
/** |
41
|
|
|
* $maxLength |
42
|
|
|
* |
43
|
|
|
* @var int |
44
|
|
|
*/ |
45
|
|
|
protected $maxLength; |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* instanciate |
49
|
|
|
* |
50
|
|
|
* @param string $streamName |
51
|
|
|
*/ |
52
|
6 |
|
public function __construct( |
53
|
|
|
string $streamName = self::STREAM_STDIN, |
54
|
|
|
string $streamMode = self::STREAM_MODE_WRITE_APPEND |
55
|
|
|
) { |
56
|
6 |
|
$this->streamName = (php_sapi_name() == self::DEBUGER) |
57
|
6 |
|
? self::STREAM_MEMORY |
58
|
|
|
: $streamName; |
59
|
6 |
|
$this->streamMode = $streamMode; |
60
|
6 |
|
$this->setMaxLength(1); |
61
|
|
|
} |
62
|
|
|
|
63
|
|
|
/** |
64
|
|
|
* return the input value |
65
|
|
|
* |
66
|
|
|
* @param string $forcedValue |
67
|
|
|
* @return string |
68
|
|
|
*/ |
69
|
1 |
|
public function value(string $forcedValue = ''): string |
70
|
|
|
{ |
71
|
1 |
|
$handle = $this->getStreamHandler(); |
72
|
|
|
//readline_callback_handler_install('', function () { }); |
73
|
1 |
|
if (!empty($forcedValue)) { |
74
|
1 |
|
$this->setMaxLength(strlen($forcedValue)); |
75
|
1 |
|
rewind($handle); |
76
|
1 |
|
fwrite($handle, $forcedValue); |
77
|
|
|
} |
78
|
1 |
|
$value = stream_get_contents( |
79
|
1 |
|
$handle, |
80
|
1 |
|
$this->getMaxLength(), |
81
|
|
|
0 |
82
|
|
|
); |
83
|
1 |
|
$this->closeStream(); |
84
|
1 |
|
return $value; |
85
|
|
|
} |
86
|
|
|
|
87
|
|
|
/** |
88
|
|
|
* set stream max length |
89
|
|
|
* |
90
|
|
|
* @return Input |
91
|
|
|
*/ |
92
|
6 |
|
public function setMaxLength(int $len): Input |
93
|
|
|
{ |
94
|
6 |
|
$this->maxLength = $len; |
95
|
6 |
|
return $this; |
96
|
|
|
} |
97
|
|
|
|
98
|
|
|
/** |
99
|
|
|
* returns stream handler |
100
|
|
|
* |
101
|
|
|
* @return int |
102
|
|
|
*/ |
103
|
1 |
|
protected function getMaxLength(): int |
104
|
|
|
{ |
105
|
1 |
|
return $this->maxLength; |
106
|
|
|
} |
107
|
|
|
|
108
|
|
|
/** |
109
|
|
|
* returns stream handler |
110
|
|
|
* |
111
|
|
|
* @return resource | null |
112
|
|
|
*/ |
113
|
1 |
|
protected function getStreamHandler() |
114
|
|
|
{ |
115
|
1 |
|
$this->openStream(); |
116
|
1 |
|
return $this->streamHandler; |
117
|
|
|
} |
118
|
|
|
|
119
|
|
|
/** |
120
|
|
|
* returns stream name |
121
|
|
|
* |
122
|
|
|
* @return string |
123
|
|
|
*/ |
124
|
1 |
|
protected function getStreamName(): string |
125
|
|
|
{ |
126
|
1 |
|
return $this->streamName; |
127
|
|
|
} |
128
|
|
|
|
129
|
|
|
/** |
130
|
|
|
* return false if streamHandler is not a resource |
131
|
|
|
* |
132
|
|
|
* @return boolean |
133
|
|
|
*/ |
134
|
|
|
protected function streamable(): bool |
135
|
|
|
{ |
136
|
|
|
return is_resource($this->streamHandler); |
137
|
|
|
} |
138
|
|
|
|
139
|
|
|
/** |
140
|
|
|
* open resource |
141
|
|
|
* |
142
|
|
|
* @return Input |
143
|
|
|
* @throws Exception |
144
|
|
|
*/ |
145
|
1 |
|
protected function openStream(): Input |
146
|
|
|
{ |
147
|
1 |
|
if (false === $this->streamable()) { |
148
|
1 |
|
$this->streamHandler = fopen($this->getStreamName(), $this->streamMode, false); |
|
|
|
|
149
|
|
|
} |
150
|
1 |
|
if (false === $this->streamable()) { |
151
|
|
|
throw new \Exception('Cant open input stream handle'); |
152
|
|
|
} |
153
|
1 |
|
return $this; |
154
|
|
|
} |
155
|
|
|
|
156
|
|
|
/** |
157
|
|
|
* close resource |
158
|
|
|
* |
159
|
|
|
* @return Input |
160
|
|
|
*/ |
161
|
1 |
|
protected function closeStream(): Input |
162
|
|
|
{ |
163
|
1 |
|
if ($this->streamable()) { |
164
|
1 |
|
fclose($this->streamHandler); |
165
|
|
|
} |
166
|
1 |
|
return $this; |
167
|
|
|
} |
168
|
|
|
} |
169
|
|
|
|
Our type inference engine has found a suspicous assignment of a value to a property. This check raises an issue when a value that can be of a mixed type is assigned to a property that is type hinted more strictly.
For example, imagine you have a variable
$accountId
that can either hold an Id object or false (if there is no account id yet). Your code now assigns that value to theid
property of an instance of theAccount
class. This class holds a proper account, so the id value must no longer be false.Either this assignment is in error or a type check should be added for that assignment.