TargetBuilder::buildWithString()   B
last analyzed

Complexity

Conditions 9
Paths 13

Size

Total Lines 32
Code Lines 24

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 9
eloc 24
nc 13
nop 1
dl 0
loc 32
rs 8.0555
c 0
b 0
f 0
1
<?php
2
namespace suda\framework\runnable\target;
3
4
use Closure;
5
use function is_array;
6
use ReflectionClass;
7
use InvalidArgumentException;
8
use ReflectionException;
9
use function sprintf;
10
use function strrpos;
11
use suda\framework\runnable\exception\InvalidNameException;
12
13
/**
14
 * 目标构造器
15
 */
16
class TargetBuilder
17
{
18
    /**
19
     * 构建目标
20
     *
21
     * @param string|array|Closure $runnable
22
     * @param array $parameter
23
     * @return RunnableTarget
24
     */
25
    public static function build($runnable, array $parameter = []):RunnableTarget
26
    {
27
        if ($runnable instanceof Closure) {
28
            return new ClosureTarget($runnable, $parameter);
29
        }
30
        if (is_array($runnable)) {
31
            return new MethodTarget($runnable[0], null, $runnable[1], $parameter);
32
        }
33
        $target = self::buildWithString($runnable);
34
        if (count($parameter) > 0) {
35
            $target->setParameter($parameter);
36
        }
37
        return $target;
38
    }
39
40
    /**
41
     * 构建可执行对象
42
     *
43
     * @param string $command
44
     * @return RunnableTarget
45
     */
46
    protected static function buildWithString(string $command):RunnableTarget
47
    {
48
        $fileStart = strrpos($command, '@');
49
        if ($fileStart === 0) {
50
            return new FileTarget(substr($command, 1));
51
        }
52
        $requireFile = '';
53
        if ($fileStart > 0) {
54
            $requireFile = substr($command, $fileStart + 1);
55
            $command = substr($command, 0, $fileStart);
56
        }
57
        // for parameter list
58
        list($command, $parameter) = self::splitParameter($command);
59
        // for method
60
        $dynmicsMethod = strpos($command, '->');
61
        $splitLength = strpos($command, '#');
62
        $methodStart = $splitLength ?: strpos($command, '::') ?: $dynmicsMethod;
63
        $parameter = self::buildParameter($parameter);
64
        if ($methodStart > 0) {
65
            $splitLength = $splitLength > 0 ? 1:2;
66
            $methodName = substr($command, $methodStart + $splitLength);
67
            $command = substr($command, 0, $methodStart);
68
            list($className, $constructParameter) = self::splitParameter($command);
69
            $constructParameter = self::buildParameter($constructParameter);
70
            $target = new MethodTarget($className, $dynmicsMethod? $constructParameter :null, $methodName, $parameter);
71
        } else {
72
            $target = new FunctionTarget(self::buildName($command), $parameter);
73
        }
74
        if (strlen($requireFile)) {
75
            $target -> setRequireFile($requireFile);
76
        }
77
        return $target;
78
    }
79
80
    /**
81
     * @param string $class
82
     * @return object
83
     * @throws ReflectionException
84
     */
85
    public static function newClassInstance(string $class)
86
    {
87
        list($className, $parameter) = self::splitParameter($class);
88
        $classRelName = self::buildName($className);
89
        if (null === $parameter) {
90
            return new  $classRelName;
91
        }
92
        $parameters = self::buildParameter($parameter);
93
        $classRef = new ReflectionClass($classRelName);
94
        return $classRef->newInstanceArgs($parameters);
95
    }
96
97
    private static function buildName(string $name)
98
    {
99
        if (preg_match('/^[\w\\\\\/.]+$/', $name) !== 1) {
100
            throw new InvalidNameException(sprintf('invalid name: %s ', $name));
101
        }
102
        return  str_replace(['.','/'], '\\', $name);
103
    }
104
105
    private static function splitParameter(string $command):array
106
    {
107
        $parameter = null;
108
        if (strrpos($command, ')') === strlen($command) - 1) {
109
            $paramStart = strpos($command, '(');
110
            $parameter = substr($command, $paramStart + 1, strlen($command) - $paramStart - 2);
111
            $command = substr($command, 0, $paramStart);
112
        }
113
        return [$command,$parameter];
114
    }
115
116
    private static function buildParameter(?string $parameter)
117
    {
118
        if (null === $parameter) {
119
            return [];
120
        }
121
        return self::parseParameter($parameter);
122
    }
123
124
    protected static function parseParameter(string $param)
125
    {
126
        $param = trim($param);
127
        if (strpos($param, '=') === 0) {
128
            list($prefix, $value) = explode(':', $param, 2);
129
            if (strpos($value, ':') === 0) {
130
                $value = base64_decode(substr($value, 1));
131
            }
132
            if ($prefix === '=j' || $prefix === '=json') {
133
                $params = json_decode($value);
134
                if (json_last_error() === JSON_ERROR_NONE) {
135
                    return $params;
136
                }
137
                throw new InvalidArgumentException(sprintf('can not parse parameter %s', $param));
138
            } else {
139
                $params = unserialize($value);
140
                if (is_object($params)) {
141
                    return [$params];
142
                }
143
                return $params;
144
            }
145
        } else {
146
            $params = explode(',', trim($param, ','));
147
            foreach ($params as $index => $value) {
148
                $params[$index] = trim($value);
149
            }
150
            return $params;
151
        }
152
    }
153
}
154