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; |
|
0 ignored issues
–
show
Bug
introduced
by
![]() |
|||
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
It seems like
substr_replace($this->string, '', $offset, 1) can also be of type array . However, the property $string is declared as type string . Maybe add an additional type check?
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 Either this assignment is in error or a type check should be added for that assignment. class Id
{
public $id;
public function __construct($id)
{
$this->id = $id;
}
}
class Account
{
/** @var Id $id */
public $id;
}
$account_id = false;
if (starsAreRight()) {
$account_id = new Id(42);
}
$account = new Account();
if ($account instanceof Id)
{
$account->id = $account_id;
}
![]() |
|||
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); |
|
0 ignored issues
–
show
|
|||
264 | } |
||
265 | 3 | ||
266 | public function __debugInfo() |
||
267 | 3 | { |
|
268 | return $this->__toString(); |
||
269 | } |
||
270 | } |
||
271 |