1 | <?php |
||
2 | |||
3 | declare(strict_types=1); |
||
4 | |||
5 | namespace PublishingKit\Utilities; |
||
6 | |||
7 | use Countable; |
||
8 | use ArrayAccess; |
||
9 | use Iterator; |
||
10 | use PublishingKit\Utilities\Contracts\Stringable; |
||
11 | use PublishingKit\Utilities\Traits\Macroable; |
||
12 | use Serializable; |
||
13 | |||
14 | /** |
||
15 | * String class |
||
16 | * @psalm-consistent-constructor |
||
17 | */ |
||
18 | class Str implements Countable, ArrayAccess, Iterator, Stringable, Serializable |
||
19 | { |
||
20 | 1 | use Macroable; |
|
21 | |||
22 | /** |
||
23 | * String |
||
24 | * |
||
25 | * @var string |
||
26 | */ |
||
27 | protected $string; |
||
28 | |||
29 | /** |
||
30 | * Position |
||
31 | * |
||
32 | * @var integer |
||
33 | */ |
||
34 | protected $position = 0; |
||
35 | |||
36 | /** |
||
37 | * Constructor |
||
38 | * |
||
39 | * @param string $string String to use. |
||
40 | * @return void |
||
41 | */ |
||
42 | 102 | public function __construct(string $string = '') |
|
43 | { |
||
44 | 102 | $this->string = $string; |
|
45 | 102 | } |
|
46 | |||
47 | /** |
||
48 | * Create string |
||
49 | * |
||
50 | * @param string $string String to use. |
||
51 | * @return Stringable |
||
52 | */ |
||
53 | 3 | public static function make(string $string): Stringable |
|
54 | { |
||
55 | 3 | return new static($string); |
|
56 | } |
||
57 | |||
58 | /** |
||
59 | * Return count of characters |
||
60 | * |
||
61 | * @return integer |
||
62 | */ |
||
63 | 9 | public function count(): int |
|
64 | { |
||
65 | 9 | return strlen($this->string); |
|
66 | } |
||
67 | |||
68 | /** |
||
69 | * Does item exist? |
||
70 | * |
||
71 | * @param mixed $offset The offset. |
||
72 | * @return boolean |
||
73 | */ |
||
74 | 3 | public function offsetExists($offset): bool |
|
75 | { |
||
76 | 3 | return isset($this->string[$offset]); |
|
77 | } |
||
78 | |||
79 | /** |
||
80 | * Get offset |
||
81 | * |
||
82 | * @param mixed $offset The offset. |
||
83 | * @return mixed |
||
84 | */ |
||
85 | 12 | public function offsetGet($offset) |
|
86 | { |
||
87 | 12 | return isset($this->string[$offset]) ? $this->string[$offset] : null; |
|
88 | } |
||
89 | |||
90 | /** |
||
91 | * Set offset |
||
92 | * |
||
93 | * @param mixed $offset The offset. |
||
94 | * @param mixed $value The value to set. |
||
95 | * @return void |
||
96 | */ |
||
97 | 6 | public function offsetSet($offset, $value): void |
|
98 | { |
||
99 | 6 | if (is_null($offset)) { |
|
100 | 3 | $this->string .= $value; |
|
101 | 3 | return; |
|
102 | } |
||
103 | 3 | $this->string[$offset] = $value; |
|
104 | 3 | } |
|
105 | |||
106 | /** |
||
107 | * Unset offset |
||
108 | * |
||
109 | * @param mixed $offset The offset. |
||
110 | * @return void |
||
111 | */ |
||
112 | 3 | public function offsetUnset($offset) |
|
113 | { |
||
114 | 3 | $this->string = substr_replace($this->string, '', $offset, 1); |
|
0 ignored issues
–
show
|
|||
115 | 3 | } |
|
116 | |||
117 | /** |
||
118 | * Get current item |
||
119 | * |
||
120 | * @return mixed |
||
121 | */ |
||
122 | 3 | public function current() |
|
123 | { |
||
124 | 3 | return $this->string[$this->position]; |
|
125 | } |
||
126 | |||
127 | /** |
||
128 | * Get key for current item |
||
129 | * |
||
130 | * @return mixed |
||
131 | */ |
||
132 | 9 | public function key() |
|
133 | { |
||
134 | 9 | return $this->position; |
|
135 | } |
||
136 | |||
137 | /** |
||
138 | * Move counter to next item |
||
139 | * |
||
140 | * @return void |
||
141 | */ |
||
142 | 6 | public function next() |
|
143 | { |
||
144 | 6 | ++$this->position; |
|
145 | 6 | } |
|
146 | |||
147 | /** |
||
148 | * Move counter back to zero |
||
149 | * |
||
150 | * @return void |
||
151 | */ |
||
152 | 3 | public function rewind() |
|
153 | { |
||
154 | 3 | $this->position = 0; |
|
155 | 3 | } |
|
156 | |||
157 | /** |
||
158 | * Is current item valid? |
||
159 | * |
||
160 | * @return boolean |
||
161 | */ |
||
162 | 3 | public function valid(): bool |
|
163 | { |
||
164 | 3 | return isset($this->string[$this->position]); |
|
165 | } |
||
166 | |||
167 | /** |
||
168 | * Convert to string |
||
169 | * |
||
170 | * @return string |
||
171 | */ |
||
172 | 27 | public function __toString(): string |
|
173 | { |
||
174 | 27 | return $this->string; |
|
175 | } |
||
176 | |||
177 | /** |
||
178 | * Find and replace text |
||
179 | * |
||
180 | * @param string $find Text to find. |
||
181 | * @param string $replace Text to replace. |
||
182 | * @return Stringable |
||
183 | */ |
||
184 | 3 | public function replace(string $find, string $replace): Stringable |
|
185 | { |
||
186 | 3 | return new static(str_replace($find, $replace, $this->string)); |
|
187 | } |
||
188 | |||
189 | /** |
||
190 | * Convert to upper case |
||
191 | * |
||
192 | * @return Stringable |
||
193 | */ |
||
194 | 3 | public function toUpper(): Stringable |
|
195 | { |
||
196 | 3 | return new static(strtoupper($this->string)); |
|
197 | } |
||
198 | |||
199 | /** |
||
200 | * Convert to lower case |
||
201 | * |
||
202 | * @return Stringable |
||
203 | */ |
||
204 | 3 | public function toLower(): Stringable |
|
205 | { |
||
206 | 3 | return new static(strtolower($this->string)); |
|
207 | } |
||
208 | |||
209 | /** |
||
210 | * Trim whitespace |
||
211 | * |
||
212 | * @return Stringable |
||
213 | */ |
||
214 | 3 | public function trim(): Stringable |
|
215 | { |
||
216 | 3 | return new static(trim($this->string)); |
|
217 | } |
||
218 | |||
219 | /** |
||
220 | * Trim left whitespace |
||
221 | * |
||
222 | * @return Stringable |
||
223 | */ |
||
224 | 3 | public function ltrim(): Stringable |
|
225 | { |
||
226 | 3 | return new static(ltrim($this->string)); |
|
227 | } |
||
228 | |||
229 | /** |
||
230 | * Trim right whitespace |
||
231 | * |
||
232 | * @return Stringable |
||
233 | */ |
||
234 | 3 | public function rtrim(): Stringable |
|
235 | { |
||
236 | 3 | return new static(rtrim($this->string)); |
|
237 | } |
||
238 | |||
239 | /** |
||
240 | * Handle path in a platform-independent way |
||
241 | * |
||
242 | * @return Stringable |
||
243 | */ |
||
244 | 3 | public function path(): Stringable |
|
245 | { |
||
246 | 3 | return new static(preg_replace('/(\\\|\/)/', DIRECTORY_SEPARATOR, $this->string)); |
|
247 | } |
||
248 | |||
249 | /** |
||
250 | * {@inheritDoc} |
||
251 | */ |
||
252 | 3 | public function serialize() |
|
253 | { |
||
254 | 3 | return serialize($this->string); |
|
255 | } |
||
256 | |||
257 | /** |
||
258 | * {@inheritDoc} |
||
259 | */ |
||
260 | 3 | public function unserialize($serialized) |
|
261 | { |
||
262 | 3 | /** @var string **/ |
|
263 | 3 | $this->string = unserialize($serialized); |
|
264 | } |
||
265 | 3 | ||
266 | public function __debugInfo() |
||
267 | 3 | { |
|
268 | return $this->__toString(); |
||
269 | } |
||
270 | } |
||
271 |
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.