-
-
Notifications
You must be signed in to change notification settings - Fork 165
Expand file tree
/
Copy pathMagicMethodDynamicPointcut.php
More file actions
93 lines (80 loc) · 3.05 KB
/
Copy pathMagicMethodDynamicPointcut.php
File metadata and controls
93 lines (80 loc) · 3.05 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
<?php
declare(strict_types=1);
/*
* Go! AOP framework
*
* @copyright Copyright 2014, Lisachenko Alexander <lisachenko.it@gmail.com>
*
* This source file is subject to the license that is bundled
* with this source code in the file LICENSE.
*/
namespace Go\Aop\Pointcut;
use Go\Aop\Pointcut;
use Go\ParserReflection\ReflectionFileNamespace;
use ReflectionClass;
use ReflectionFunction;
use ReflectionMethod;
use ReflectionProperty;
/**
* Magic method pointcut is a dynamic checker that verifies calls for __call and __callStatic
*
* With one (or two) arguments it always statically matches with __call and __callStatic methods.
* With four arguments, it takes real argument for invocation and matches it again dynamically.
*/
final readonly class MagicMethodDynamicPointcut implements Pointcut
{
/**
* Compiled regular expression for matching
*/
private string $regexp;
/**
* Magic method matcher constructor
*
* @param string $methodName Method name to match, can contain wildcards "*","?" or "|"
*/
public function __construct(private string $methodName) {
$this->regexp = '/^(' . strtr(
preg_quote($this->methodName, '/'),
[
'\\*' => '.*?',
'\\?' => '.',
'\\|' => '|'
]
) . ')$/';
}
public function matches(
ReflectionClass|ReflectionFileNamespace $context,
ReflectionMethod|ReflectionProperty|ReflectionFunction|null $reflector = null,
null|object|string $instanceOrScope = null,
?array $arguments = null
): bool {
// Magic methods can be only inside class context
if (!$context instanceof ReflectionClass) {
return false;
}
// For pre-filter we match only with context that has magic methods
if (!isset($reflector)) {
return $context->hasMethod('__call') || $context->hasMethod('__callStatic');
}
// If we receive something not expected here (ReflectionMethod), we should not match
if (!$reflector instanceof ReflectionMethod) {
return false;
}
// With single parameter (statically) always matches for __call, __callStatic methods
if ($instanceOrScope === null) {
return ($reflector->name === '__call' || $reflector->name === '__callStatic');
}
// If for some reason we don't have arguments, or first argument is not a string with valid function name
if (!isset($arguments) || count($arguments) < 1 || !is_string($arguments[0])) {
return false;
}
// for __call and __callStatic method name is the first argument on invocation
[$methodName] = $arguments;
// Perform final dynamic check
return ($methodName === $this->methodName) || preg_match($this->regexp, $methodName);
}
public function getKind(): int
{
return Pointcut::KIND_METHOD | Pointcut::KIND_DYNAMIC;
}
}