Passed
Push — master ( c1e721...8ec156 )
by 世昌
02:05
created

TargetBuilder::parseParameter()   B

Complexity

Conditions 8
Paths 10

Size

Total Lines 27
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

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