1
|
|
|
<?php |
2
|
|
|
|
3
|
|
|
namespace mpyw\Co\Internal; |
4
|
|
|
|
5
|
|
|
use mpyw\Co\CoInterface; |
6
|
|
|
use mpyw\Co\Internal\GeneratorContainer; |
7
|
|
|
|
8
|
|
|
class Utils { |
9
|
|
|
|
10
|
|
|
/** |
11
|
|
|
* Recursively normalize value. |
12
|
|
|
* Generator Closure -> GeneratorContainer |
13
|
|
|
* Array -> Array (children's are normalized) |
14
|
|
|
* Others -> Others |
15
|
|
|
* @param mixed $value |
16
|
|
|
* @param CoOption $options |
17
|
|
|
* @param mixed $yield_key |
18
|
|
|
* @return mixed |
19
|
|
|
*/ |
20
|
|
|
public static function normalize($value, CoOption $options, $yield_key = null) |
21
|
|
|
{ |
22
|
16 |
|
if (self::isGeneratorClosure($value)) { |
23
|
16 |
|
$value = $value(); |
24
|
16 |
|
} |
25
|
|
|
if ($value instanceof \Generator) { |
26
|
16 |
|
return new GeneratorContainer($value, $options, $yield_key); |
27
|
7 |
|
} |
28
|
5 |
|
if (is_array($value)) { |
29
|
5 |
|
$tmp = []; |
30
|
4 |
|
foreach ($value as $k => $v) { |
31
|
|
|
$tmp[$k] = self::normalize($v, $options, $yield_key); |
32
|
|
|
} |
33
|
|
|
return $tmp; |
34
|
16 |
|
} |
35
|
16 |
|
return $value; |
36
|
|
|
} |
37
|
13 |
|
|
38
|
9 |
|
/** |
39
|
9 |
|
* Recursively search yieldable values. |
40
|
9 |
|
* Each entries are assoc those contain keys 'value' and 'keylist'. |
41
|
|
|
* value -> the value itself. |
42
|
8 |
|
* keylist -> position of the value. nests are represented as array values. |
43
|
|
|
* @param mixed $value Must be already normalized. |
44
|
13 |
|
* @param array $keylist Internally used. |
45
|
|
|
* @return array |
46
|
|
|
*/ |
47
|
|
|
public static function getYieldables($value, array $keylist = []) |
48
|
|
|
{ |
49
|
|
|
$r = []; |
50
|
|
|
if (!is_array($value)) { |
51
|
|
|
if (self::isCurl($value) || self::isGeneratorContainer($value)) { |
52
|
|
|
$r[(string)$value] = [ |
53
|
|
|
'value' => $value, |
54
|
|
|
'keylist' => $keylist, |
55
|
|
|
]; |
56
|
13 |
|
} |
57
|
13 |
|
return $r; |
58
|
13 |
|
} |
59
|
13 |
|
foreach ($value as $k => $v) { |
60
|
13 |
|
$newlist = array_merge($keylist, [$k]); |
61
|
11 |
|
$r = array_merge($r, self::getYieldables($v, $newlist)); |
62
|
11 |
|
} |
63
|
11 |
|
return $r; |
64
|
|
|
} |
65
|
|
|
|
66
|
13 |
|
/** |
67
|
|
|
* Check if value is a valid cURL handle. |
68
|
8 |
|
* @param mixed $value |
69
|
8 |
|
* @return bool |
70
|
8 |
|
*/ |
71
|
|
|
public static function isCurl($value) |
72
|
8 |
|
{ |
73
|
|
|
return is_resource($value) && get_resource_type($value) === 'curl'; |
74
|
|
|
} |
75
|
|
|
|
76
|
|
|
/** |
77
|
|
|
* Check if value is a valid Generator. |
78
|
|
|
* @param mixed $value |
79
|
|
|
* @return bool |
80
|
14 |
|
*/ |
81
|
14 |
|
public static function isGeneratorContainer($value) |
82
|
2 |
|
{ |
83
|
|
|
return $value instanceof GeneratorContainer; |
84
|
|
|
} |
85
|
|
|
|
86
|
|
|
/** |
87
|
|
|
* Check if value is a valid Generator closure. |
88
|
|
|
* @param mixed $value |
89
|
|
|
* @return bool |
90
|
14 |
|
*/ |
91
|
14 |
|
public static function isGeneratorClosure($value) |
92
|
14 |
|
{ |
93
|
|
|
return $value instanceof \Closure |
94
|
|
|
&& (new \ReflectionFunction($value))->isGenerator(); |
|
|
|
|
95
|
|
|
} |
96
|
|
|
|
97
|
|
|
} |
98
|
|
|
|
Let’s take a look at an example:
In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.
Available Fixes
Change the type-hint for the parameter:
Add an additional type-check:
Add the method to the parent class: