Issues (20)

src/Utilities/ClassMethodHandler.php (7 issues)

Labels
Severity
1
<?php
2
3
namespace Ballen\Clip\Utilities;
4
5
use Ballen\Clip\Interfaces\CommandInterface;
6
7
/**
8
 * Clip
9
 * 
10
 * A package for speeding up development of PHP console (CLI) applications.
11
 *
12
 * @author Bobby Allen <[email protected]>
13
 * @license https://raw.githubusercontent.com/bobsta63/clip/master/LICENSE
14
 * @link https://github.com/allebb/clip
15
 * @link http://www.bobbyallen.me
16
 *
17
 */
18
class ClassMethodHandler
19
{
20
21
    /**
22
     * Character for splitting the "dot" notation on command handlers.
23
     */
24
    const CHAR_DOT = '.';
25
26
    /**
27
     * Character for splitting the "at" notation on command handlers.
28
     */
29
    const CHAR_AT = '@';
30
31
    /**
32
     * Class of which will be instantiated at runtime.
33
     * @var string 
34
     */
35
    protected $class;
36
37
    /**
38
     * The method of which should be called at runtime.
39
     * @var string
40
     */
41
    protected $method = 'handle';
42
43
    /**
44
     * Optional argument(s) to pass through when calling the Class contructor.
45
     * @var mixed
46
     */
47
    protected $constructor_arguments;
48
49
    /**
50
     * Creates a new instance
51
     * @param string|array $handler
52
     * @param array $constructor_arguments Optional arguments to pass to the class constructor.
53
     */
54 24
    public function __construct($handler, $constructor_arguments = [])
55
    {
56 24
        $this->constructor_arguments = $constructor_arguments;
57 24
        $this->extract($handler);
58 16
        $this->validate();
59
    }
60
61
    /**
62
     * Calls the requested class and method name passing in the optional arguments.
63
     * @param mixed $params Optional parameters to pass to the class method.
64
     * @return void
65
     */
66 8
    public function call($params = null)
67
    {
68 8
        $method = $this->method;
69
70 8
        if (!empty($this->constructor_arguments)) {
71 8
            $instance = new $this->class($this->constructor_arguments);
72
        } else {
73
            $instance = new $this->class();
74
        }
75 8
        if (!is_null($params)) {
76 8
            return $instance->$method($params);
77
        }
78
        return $instance->$method();
79
    }
80
81
    /**
82
     * Extracts the class and method name.
83
     * @param string|array $handler The handler parameter
84
     * @return void
85
     */
86 24
    private function extract($handler)
87
    {
88 24
        if (is_array($handler)) {
89 6
            return $this->fromClassMethodArray($handler);
0 ignored issues
show
Are you sure the usage of $this->fromClassMethodArray($handler) targeting Ballen\Clip\Utilities\Cl...:fromClassMethodArray() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
90
        }
91 18
        if (strpos($handler, self::CHAR_AT) !== false) {
92 8
            return $this->fromAtNotation($handler);
0 ignored issues
show
Are you sure the usage of $this->fromAtNotation($handler) targeting Ballen\Clip\Utilities\Cl...ndler::fromAtNotation() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
93
        }
94 10
        if (strpos($handler, self::CHAR_DOT) !== false) {
95 6
            return $this->fromDotNotation($handler);
0 ignored issues
show
Are you sure the usage of $this->fromDotNotation($handler) targeting Ballen\Clip\Utilities\Cl...dler::fromDotNotation() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
96
        }
97 4
        return $this->fromClassName($handler);
0 ignored issues
show
Are you sure the usage of $this->fromClassName($handler) targeting Ballen\Clip\Utilities\Cl...andler::fromClassName() seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
98
    }
99
100
    /**
101
     * Validates that the current class and methods exist and are callable.
102
     * @return void
103
     * @throws \RuntimeException
104
     */
105 16
    private function validate()
106
    {
107 16
        if (!class_exists($this->class)) {
108 2
            throw new \RuntimeException(sprintf('Class %s does not exist, is this the correct namespace?', $this->class));
109
        }
110 14
        if (!in_array($this->method, get_class_methods($this->class))) {
111 6
            throw new \RuntimeException(sprintf('The method "%s" does not exist in "%s" class.', $this->method, $this->class));
112
        }
113
    }
114
115
    /**
116
     * Extracts the class name and method from the Class Method string in "@" notation (eg. Class@Method).
117
     * @param string|array $handler The handler parameter
118
     * @return void
119
     * @throws \InvalidArgumentException
120
     */
121 8
    private function fromAtNotation($handler)
122
    {
123 8
        $parts = explode(self::CHAR_AT, $handler);
0 ignored issues
show
It seems like $handler can also be of type array; however, parameter $string of explode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

123
        $parts = explode(self::CHAR_AT, /** @scrutinizer ignore-type */ $handler);
Loading history...
124 8
        if (count($parts) != 2) {
125 2
            throw new \InvalidArgumentException('Invalid Class Method format from "at" notation.');
126
        }
127 6
        $this->class = $parts[0];
128 6
        $this->method = $parts[1];
129
    }
130
131
    /**
132
     * Extracts the class name and method from the Class Method string in "dot" notation (eg. Class.Method).
133
     * @param string|array $handler The handler parameter
134
     * @return void
135
     * @throws \InvalidArgumentException
136
     */
137 6
    private function fromDotNotation($handler)
138
    {
139 6
        $parts = explode(self::CHAR_DOT, $handler);
0 ignored issues
show
It seems like $handler can also be of type array; however, parameter $string of explode() does only seem to accept string, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

139
        $parts = explode(self::CHAR_DOT, /** @scrutinizer ignore-type */ $handler);
Loading history...
140 6
        if (count($parts) != 2) {
141 2
            throw new \InvalidArgumentException('Invalid Class Method format from "dot" notation.');
142
        }
143 4
        $this->class = $parts[0];
144 4
        $this->method = $parts[1];
145
    }
146
147
    /**
148
     * Extracts the class name (no method present) from a single string.
149
     * @param string $handler The handler parameter
150
     * @return void
151
     * @throws \InvalidArgumentException
152
     */
153 4
    private function fromClassName($handler)
154
    {
155 4
        if (!is_subclass_of($handler, CommandInterface::class)) {
156 2
            throw new \InvalidArgumentException(sprintf('The command class must implement the "CommandInterface" interface.'));
157
        }
158 2
        $this->class = $handler;
159
    }
160
161
    /**
162
     * Extracts the class and method name from an array eg (['Class', 'Method'])
163
     * @param string|array $handler The handler parameter
164
     * @return void
165
     * @throws \InvalidArgumentException
166
     */
167 6
    private function fromClassMethodArray($handler)
168
    {
169 6
        if (count($handler) != 2) {
0 ignored issues
show
It seems like $handler can also be of type string; however, parameter $value of count() does only seem to accept Countable|array, maybe add an additional type check? ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-type  annotation

169
        if (count(/** @scrutinizer ignore-type */ $handler) != 2) {
Loading history...
170 2
            throw new \InvalidArgumentException('Class method array constructor can only contain 2 elements.');
171
        }
172 4
        $this->class = $handler[0];
173 4
        $this->method = $handler[1];
174
    }
175
}
176