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