Passed
Push — master ( 516163...07b934 )
by 世昌
02:15
created

TargetBuilder   A

Complexity

Total Complexity 29

Size/Duplication

Total Lines 131
Duplicated Lines 0 %

Importance

Changes 0
Metric Value
eloc 73
dl 0
loc 131
rs 10
c 0
b 0
f 0
wmc 29

7 Methods

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