1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
declare(strict_types=1); |
4
|
|
|
|
5
|
|
|
namespace Conia\Boiler; |
6
|
|
|
|
7
|
|
|
use Conia\Boiler\Exception\RuntimeException; |
8
|
|
|
use Symfony\Component\HtmlSanitizer\HtmlSanitizerConfig; |
9
|
|
|
use Throwable; |
10
|
|
|
|
11
|
|
|
/** @psalm-api */ |
12
|
|
|
class Value implements ValueInterface |
13
|
|
|
{ |
14
|
61 |
|
public function __construct(protected readonly mixed $value) |
15
|
|
|
{ |
16
|
61 |
|
} |
17
|
|
|
|
18
|
36 |
|
public function __toString(): string |
19
|
|
|
{ |
20
|
36 |
|
return htmlspecialchars( |
21
|
36 |
|
(string)$this->value, |
22
|
36 |
|
ENT_QUOTES | ENT_SUBSTITUTE, |
23
|
36 |
|
'UTF-8', |
24
|
36 |
|
); |
25
|
|
|
} |
26
|
|
|
|
27
|
4 |
|
public function __get(string $name): mixed |
28
|
|
|
{ |
29
|
|
|
try { |
30
|
|
|
/** |
31
|
|
|
* @psalm-suppress MixedPropertyFetch |
32
|
|
|
* |
33
|
|
|
* Wrapper::wrap checks types |
34
|
|
|
*/ |
35
|
4 |
|
return Wrapper::wrap($this->value->{$name}); |
36
|
2 |
|
} catch (Throwable) { |
37
|
2 |
|
throw new RuntimeException('No such property'); |
38
|
|
|
} |
39
|
|
|
} |
40
|
|
|
|
41
|
3 |
|
public function __set(string $name, mixed $value): void |
42
|
|
|
{ |
43
|
|
|
try { |
44
|
3 |
|
$this->value->{$name} = $value; |
45
|
|
|
|
46
|
1 |
|
return; |
47
|
2 |
|
} catch (Throwable) { |
|
|
|
|
48
|
2 |
|
throw new RuntimeException('No such property'); |
49
|
|
|
} |
50
|
|
|
} |
51
|
|
|
|
52
|
13 |
|
public function __call(string $name, array $args): mixed |
53
|
|
|
{ |
54
|
13 |
|
if (is_callable([$this->value, $name])) { |
55
|
12 |
|
return Wrapper::wrap($this->value->{$name}(...$args)); |
56
|
|
|
} |
57
|
|
|
|
58
|
1 |
|
throw new RuntimeException('No such method'); |
59
|
|
|
} |
60
|
|
|
|
61
|
3 |
|
public function __invoke(mixed ...$args): mixed |
62
|
|
|
{ |
63
|
3 |
|
if (is_callable($this->value)) { |
64
|
2 |
|
return Wrapper::wrap(($this->value)(...$args)); |
65
|
|
|
} |
66
|
|
|
|
67
|
1 |
|
throw new RuntimeException('No such method'); |
68
|
|
|
} |
69
|
|
|
|
70
|
12 |
|
public function unwrap(): mixed |
71
|
|
|
{ |
72
|
12 |
|
return $this->value; |
73
|
|
|
} |
74
|
|
|
|
75
|
1 |
|
public function strip(array|string|null $allowed = null): string |
76
|
|
|
{ |
77
|
|
|
/** |
78
|
|
|
* As of now (early 2023), psalm does not support the |
79
|
|
|
* type array as arguments to strip_tags's $allowed_tags. |
80
|
|
|
* |
81
|
|
|
* @psalm-suppress PossiblyInvalidArgument |
82
|
|
|
*/ |
83
|
1 |
|
return strip_tags((string)$this->value, $allowed); |
84
|
|
|
} |
85
|
|
|
|
86
|
4 |
|
public function clean( |
87
|
|
|
HtmlSanitizerConfig $config = null, |
88
|
|
|
bool $removeEmptyLines = true |
89
|
|
|
): string { |
90
|
4 |
|
return Sanitizer::clean((string)$this->value, $config, $removeEmptyLines); |
91
|
|
|
} |
92
|
|
|
|
93
|
2 |
|
public function empty(): bool |
94
|
|
|
{ |
95
|
2 |
|
return empty($this->value); |
96
|
|
|
} |
97
|
|
|
} |
98
|
|
|
|
This check looks for unreachable code. It uses sophisticated control flow analysis techniques to find statements which will never be executed.
Unreachable code is most often the result of
return
,die
orexit
statements that have been added for debug purposes.In the above example, the last
return false
will never be executed, because a return statement has already been met in every possible execution path.