Issues (54)

src/TokenStream/CallableUserMethod.php (1 issue)

Labels
Severity
1
<?php declare(strict_types=1);
2
3
/**
4
 * @license     http://opensource.org/licenses/mit-license.php MIT
5
 * @link        https://github.com/nicoSWD
6
 * @author      Nicolas Oelgart <[email protected]>
7
 */
8
namespace nicoSWD\Rule\TokenStream;
9
10
use Closure;
11
use nicoSWD\Rule\Grammar\CallableUserFunctionInterface;
12
use nicoSWD\Rule\TokenStream\Token\BaseToken;
13
use nicoSWD\Rule\TokenStream\Token\TokenFactory;
0 ignored issues
show
The type nicoSWD\Rule\TokenStream\Token\TokenFactory was not found. Maybe you did not declare it correctly or list all dependencies?

The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
14
15
final class CallableUserMethod implements CallableUserFunctionInterface
16
{
17
    private const MAGIC_METHOD_PREFIX = '__';
18
19
    private TokenFactory $tokenFactory;
20
    private Closure $callable;
21
    private array $methodPrefixes = ['', 'get', 'is', 'get_', 'is_'];
22
23
    /**
24
     * @throws Exception\UndefinedMethodException
25
     * @throws Exception\ForbiddenMethodException
26
     */
27
    public function __construct(BaseToken $token, TokenFactory $tokenFactory, string $methodName)
28
    {
29 52
        $this->tokenFactory = $tokenFactory;
30
        $this->callable = $this->getCallable($token, $methodName);
31 52
    }
32 52
33 18
    public function call(?BaseToken ...$param): BaseToken
34
    {
35 18
        $callableCopy = $this->callable;
36
37 18
        return $this->tokenFactory->createFromPHPType(
38
            $callableCopy(...$param)
39 18
        );
40 18
    }
41
42
    /**
43
     * @throws Exception\UndefinedMethodException
44
     * @throws Exception\ForbiddenMethodException
45
     */
46
    private function getCallable(BaseToken $token, string $methodName): Closure
47
    {
48 52
        $object = $token->getValue();
49
50 52
        if (property_exists($object, $methodName)) {
51
            return fn () => $object->{$methodName};
52 52
        }
53
54 4
        $method = $this->findCallableMethod($object, $methodName);
55 4
56
        return fn (?BaseToken ...$params) => $method(
57
            ...$this->getTokenValues($params)
58 48
        );
59
    }
60
61 14
    /**
62 14
     * @throws Exception\UndefinedMethodException
63
     * @throws Exception\ForbiddenMethodException
64
     */
65
    private function findCallableMethod(object $object, string $methodName): callable
66
    {
67
        $this->assertNonMagicMethod($methodName);
68
        $index = 0;
69 48
70
        do {
71 48
            if (!isset($this->methodPrefixes[$index])) {
72
                throw new Exception\UndefinedMethodException();
73 18
            }
74 18
75
            $callableMethod = $this->methodPrefixes[$index++] . $methodName;
76
        } while (!is_callable([$object, $callableMethod]));
77 18
78 4
        return [$object, $callableMethod];
79
    }
80
81 18
    private function getTokenValues(array $params): array
82 18
    {
83
        $values = [];
84 14
85
        foreach ($params as $token) {
86
            $values[] = $token->getValue();
87 14
        }
88
89 14
        return $values;
90
    }
91 14
92 4
    /** @throws Exception\ForbiddenMethodException */
93
    private function assertNonMagicMethod(string $methodName): void
94
    {
95 14
        if (str_starts_with($methodName, self::MAGIC_METHOD_PREFIX)) {
96
            throw new Exception\ForbiddenMethodException();
97
        }
98
    }
99
}
100