Completed
Push — master ( 7c37a7...99527b )
by Oleg
03:04
created

Micro::initializeContainer()   A

Complexity

Conditions 4
Paths 8

Size

Total Lines 19
Code Lines 11

Duplication

Lines 0
Ratio 0 %

Importance

Changes 4
Bugs 1 Features 1
Metric Value
c 4
b 1
f 1
dl 0
loc 19
rs 9.2
cc 4
eloc 11
nc 8
nop 0
1
<?php /** Micro */
2
3
namespace Micro;
4
5
use Micro\base\Container;
6
use Micro\base\Dispatcher;
7
use Micro\Base\Exception;
8
use Micro\Base\FatalError;
9
use Micro\Base\ICommand;
10
use Micro\base\IContainer;
11
use Micro\cli\Consoles\DefaultConsoleCommand;
12
use Micro\Mvc\Controllers\IController;
13
use Micro\Resolver\IResolver;
14
use Micro\web\IOutput;
15
use Micro\web\IRequest;
16
use Micro\Web\IResponse;
17
use Micro\web\Response;
18
19
/**
20
 * Micro class file.
21
 *
22
 * Base class for initialize MicroPHP, used as bootstrap framework.
23
 *
24
 * @author Oleg Lunegov <[email protected]>
25
 * @link https://github.com/lugnsk/micro
26
 * @copyright Copyright &copy; 2013 Oleg Lunegov
27
 * @license /LICENSE
28
 * @package micro
29
 * @version 1.0
30
 * @since 1.0
31
 */
32
class Micro
33
{
34
    /** @const string VERSION Version framework */
35
    const VERSION = '1.1';
36
37
    /** @var IContainer $container Container is a container for components and options */
38
    protected $container;
39
    /** @var string $appDir */
40
    protected $appDir;
41
42
    /** @var bool $loaded Micro loaded flag */
43
    private $loaded;
44
    /** @var bool $debug Debug-mode flag */
45
    private $debug = true;
46
    /** @var string $environment Application environment */
47
    private $environment = 'devel';
48
    /** @var float $startTime Time of start framework */
49
    private $startTime;
50
51
52
    /**
53
     * Initialize application
54
     *
55
     * @access public
56
     *
57
     * @param string $environment Application environment: devel , production , test, other
58
     * @param bool $debug Debug-mode flag
59
     *
60
     * @result void
61
     */
62
    public function __construct($environment = 'devel', $debug = true)
63
    {
64
        $this->environment = (string)$environment;
65
        $this->debug = (bool)$debug;
66
        $this->loaded = false;
67
68
        ini_set('display_errors', (integer)$this->debug);
69
70
        FatalError::register();
71
72
        if ($this->debug) {
73
            $this->startTime = microtime(true);
74
        }
75
    }
76
77
    /**
78
     * Clone application
79
     *
80
     * @access public
81
     *
82
     * @return void
83
     */
84
    public function __clone()
85
    {
86
        if ($this->debug) { // start new timer
87
            $this->startTime = microtime(true);
88
        }
89
90
        $this->loaded = false; // deactivate loaded
91
        $this->container = null; // remove configured container
92
    }
93
94
    /**
95
     * Running application
96
     *
97
     * @access public
98
     *
99
     * @param IRequest $request Request object
100
     *
101
     * @return Response
102
     * @throws \Exception
103
     */
104
    public function run(IRequest $request)
105
    {
106
        try {
107
            return $this->doRun($request);
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->doRun($request); of type Micro\Web\IResponse|string adds the type string to the return on line 107 which is incompatible with the return type documented by Micro\Micro::run of type Micro\Web\Response.
Loading history...
108
        } catch (\Exception $e) {
109
            if ($this->debug) {
110
                $this->container->dispatcher->signal('kernel.exception', ['exception' => $e]);
0 ignored issues
show
Bug introduced by
Accessing dispatcher on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
111
                throw $e;
112
            }
113
114
            return $this->doException($e); // run exception
0 ignored issues
show
Bug Compatibility introduced by
The expression $this->doException($e); of type Micro\Cli\Consoles\Defau...mand|Micro\Web\Response adds the type Micro\Cli\Consoles\DefaultConsoleCommand to the return on line 114 which is incompatible with the return type documented by Micro\Micro::run of type Micro\Web\Response.
Loading history...
115
        }
116
    }
117
118
    /**
119
     * Initialization container
120
     *
121
     * @access protected
122
     * @return void
123
     */
124
    protected function initializeContainer()
125
    {
126
        $class = $this->getContainerClass();
127
        if ($class) {
128
            $class = new $class;
129
        }
130
131
        $this->container = ($class instanceof IContainer) ? $class : new Container;
132
        $this->container->kernel = $this;
0 ignored issues
show
Bug introduced by
Accessing kernel on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
133
        $this->container->load($this->getConfig());
134
135
        if (false === $this->container->dispatcher) {
0 ignored issues
show
Bug introduced by
Accessing dispatcher on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
136
            $this->container->dispatcher = new Dispatcher;
0 ignored issues
show
Bug introduced by
Accessing dispatcher on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
137
        }
138
139
        $this->container->dispatcher->signal('kernel.boot', ['container' => $this->container]);
0 ignored issues
show
Bug introduced by
Accessing dispatcher on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
140
141
        $this->loaded = true;
142
    }
143
144
    /**
145
     * Get full class name
146
     * @return string
147
     */
148
    protected function getContainerClass()
149
    {
150
        return '';
151
    }
152
153
    /**
154
     * Default config path
155
     *
156
     * @return string
157
     */
158
    protected function getConfig()
159
    {
160
        return $this->getAppDir() . '/configs/index.php';
161
    }
162
163
    /**
164
     * Get application directory
165
     *
166
     * @return string
167
     */
168
    public function getAppDir()
169
    {
170
        if (!$this->appDir) {
171
            $this->appDir = realpath(dirname((new \ReflectionObject($this))->getFileName()));
172
        }
173
174
        return $this->appDir;
175
    }
176
177
    /**
178
     * Add listener on event
179
     *
180
     * @access public
181
     *
182
     * @param string $listener listener name
183
     * @param mixed $event ['Object', 'method'] or callable
184
     * @param int|null $prior priority
185
     *
186
     * @return bool
187
     */
188
    protected function addListener($listener, $event, $prior = null)
189
    {
190
        if (!is_string($listener) || !$this->container) {
191
            return false;
192
        }
193
194
        $this->container->dispatcher->addListener($listener, $event, $prior);
0 ignored issues
show
Bug introduced by
Accessing dispatcher on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
195
196
        return true;
197
    }
198
199
    /**
200
     * Send signal to dispatcher
201
     *
202
     * @param $signal
203
     * @param $params
204
     * @return mixed
205
     */
206
    protected function sendSignal($signal, $params)
207
    {
208
        return $this->container->dispatcher->signal($signal, $params);
0 ignored issues
show
Bug introduced by
Accessing dispatcher on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
209
    }
210
211
    /**
212
     * Get start time
213
     *
214
     * @access public
215
     *
216
     * @return float|null
217
     */
218
    public function getStartTime()
219
    {
220
        return $this->startTime;
221
    }
222
223
    /**
224
     * Starting ...
225
     *
226
     * @access private
227
     *
228
     * @param IRequest $request
229
     *
230
     * @return Web\IResponse|Response|string
231
     * @throws \Micro\Base\Exception
232
     */
233
    private function doRun(IRequest $request)
234
    {
235
        if (!$this->loaded) {
236
            $this->initializeContainer();
237
238
            $this->addListener('kernel.kill', function (array $params) {
239
                if ($params['container']->kernel->isDebug() && !$params['container']->request->isCli()) {
240
                    // Add timer into page
241
                    echo '<div class=debug_timer>', (microtime(true) - $params['container']->kernel->getStartTime()), '</div>';
242
                }
243
244
                if (false === $params['container']->kernel->loaded) {
245
                    return;
246
                }
247
248
                $params['container']->kernel->container = null;
249
                $params['container']->kernel->loaded = false;
250
            });
251
        }
252
253
        $this->container->request = $request;
0 ignored issues
show
Bug introduced by
Accessing request on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
254
        if ($output = $this->sendSignal('kernel.request', ['container' => $this->container]) instanceof IResponse) {
255
            return $output;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $output; (boolean) is incompatible with the return type documented by Micro\Micro::doRun of type Micro\Web\IResponse|string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
256
        }
257
258
        /** @var IResolver $resolver */
259
        $resolver = $this->getResolver();
260
        if ($output = $this->sendSignal('kernel.router', ['resolver' => $resolver]) instanceof IResponse) {
261
            return $output;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $output; (boolean) is incompatible with the return type documented by Micro\Micro::doRun of type Micro\Web\IResponse|string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
262
        }
263
264
        /** @var IController|ICommand $app */
265
        $app = $resolver->getApplication();
266
        if ($output = $this->sendSignal('kernel.controller', ['application' => $app]) instanceof IResponse) {
267
            return $output;
0 ignored issues
show
Bug Best Practice introduced by
The return type of return $output; (boolean) is incompatible with the return type documented by Micro\Micro::doRun of type Micro\Web\IResponse|string.

If you return a value from a function or method, it should be a sub-type of the type that is given by the parent type f.e. an interface, or abstract method. This is more formally defined by the Lizkov substitution principle, and guarantees that classes that depend on the parent type can use any instance of a child type interchangably. This principle also belongs to the SOLID principles for object oriented design.

Let’s take a look at an example:

class Author {
    private $name;

    public function __construct($name) {
        $this->name = $name;
    }

    public function getName() {
        return $this->name;
    }
}

abstract class Post {
    public function getAuthor() {
        return 'Johannes';
    }
}

class BlogPost extends Post {
    public function getAuthor() {
        return new Author('Johannes');
    }
}

class ForumPost extends Post { /* ... */ }

function my_function(Post $post) {
    echo strtoupper($post->getAuthor());
}

Our function my_function expects a Post object, and outputs the author of the post. The base class Post returns a simple string and outputting a simple string will work just fine. However, the child class BlogPost which is a sub-type of Post instead decided to return an object, and is therefore violating the SOLID principles. If a BlogPost were passed to my_function, PHP would not complain, but ultimately fail when executing the strtoupper call in its body.

Loading history...
268
        }
269
270
        $output = $app->action($resolver->getAction());
0 ignored issues
show
Bug introduced by
The method action does only exist in Micro\Mvc\Controllers\IController, but not in Micro\Base\ICommand.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
271
        if (!$output instanceof IOutput) {
272
            $response = $this->container->response ?: new Response;
0 ignored issues
show
Bug introduced by
Accessing response on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
273
            $response->setBody((string)$output);
274
            $output = $response;
275
        }
276
277
        $this->sendSignal('kernel.response', ['output' => $output]);
278
279
        return $output;
280
    }
281
282
    /**
283
     * Get resolver
284
     *
285
     * @access protected
286
     *
287
     * @return IResolver
288
     * @throws \Micro\Base\Exception
289
     */
290
    protected function getResolver()
291
    {
292
        if ($this->container->request->isCli()) {
0 ignored issues
show
Bug introduced by
Accessing request on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
293
            $resolver = $this->container->consoleResolver ?: '\Micro\resolver\ConsoleResolver';
0 ignored issues
show
Bug introduced by
Accessing consoleResolver on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
294
        } else {
295
            $resolver = $this->container->resolver ?: '\Micro\Resolver\HMVCResolver';
0 ignored issues
show
Bug introduced by
Accessing resolver on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
296
        }
297
298
        if (is_string($resolver) && is_subclass_of($resolver, '\Micro\Resolver\IResolver')) {
299
            $resolver = new $resolver($this->container);
300
        }
301
302
        if (!$resolver instanceof IResolver) {
303
            throw new Exception('Resolver is not implement an IResolver');
304
        }
305
306
        return $resolver;
307
    }
308
309
    /**
310
     * Do exception
311
     *
312
     * @access private
313
     *
314
     * @param \Exception $e Exception
315
     *
316
     * @return IOutput
317
     * @throws \Micro\base\Exception
318
     */
319
    private function doException(\Exception $e)
320
    {
321
        $output = $this->container->request->isCli() ? new DefaultConsoleCommand([]) : new Response();
0 ignored issues
show
Bug introduced by
Accessing request on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
322
323
        if ($this->container->request->isCli()) {
0 ignored issues
show
Bug introduced by
Accessing request on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
324
            $output->data = '"Error #' . $e->getCode() . ' - ' . $e->getMessage() . '"';
325
            $output->execute();
0 ignored issues
show
Bug introduced by
The method execute does only exist in Micro\Cli\Consoles\DefaultConsoleCommand, but not in Micro\Web\Response.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
326
327
            return $output;
328
        }
329
        if (!$this->container->errorController || !$this->container->errorAction) {
0 ignored issues
show
Bug introduced by
Accessing errorController on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
Bug introduced by
Accessing errorAction on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
330
            $output->setBody('Option `errorController` or `errorAction` not configured');
0 ignored issues
show
Bug introduced by
The method setBody does only exist in Micro\Web\Response, but not in Micro\Cli\Consoles\DefaultConsoleCommand.

It seems like the method you are trying to call exists only in some of the possible types.

Let’s take a look at an example:

class A
{
    public function foo() { }
}

class B extends A
{
    public function bar() { }
}

/**
 * @param A|B $x
 */
function someFunction($x)
{
    $x->foo(); // This call is fine as the method exists in A and B.
    $x->bar(); // This method only exists in B and might cause an error.
}

Available Fixes

  1. Add an additional type-check:

    /**
     * @param A|B $x
     */
    function someFunction($x)
    {
        $x->foo();
    
        if ($x instanceof B) {
            $x->bar();
        }
    }
    
  2. Only allow a single type to be passed if the variable comes from a parameter:

    function someFunction(B $x) { /** ... */ }
    
Loading history...
331
332
            return $output;
333
        }
334
        $this->container->request->setPost('error', $e);
0 ignored issues
show
Bug introduced by
Accessing request on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
335
336
        $controller = $this->container->errorController;
0 ignored issues
show
Bug introduced by
Accessing errorController on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
337
338
        /** @var \Micro\mvc\controllers\IController $result */
339
        $result = new $controller($this->container, false);
340
        $result = $result->action($this->container->errorAction);
0 ignored issues
show
Bug introduced by
Accessing errorAction on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
341
        if ($result instanceof IOutput) {
342
            return $result;
343
        }
344
345
        $output->setBody($result);
0 ignored issues
show
Bug introduced by
It seems like $result defined by $result->action($this->container->errorAction) on line 340 can also be of type object<Micro\Web\IResponse>; however, Micro\Web\Response::setBody() does only seem to accept string, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
346
347
        return $output;
348
    }
349
350
    /**
351
     * Terminate application
352
     *
353
     * @access public
354
     *
355
     * @return void
356
     */
357
    public function terminate()
358
    {
359
        $this->container->dispatcher->signal('kernel.kill', ['container' => $this->container]);
0 ignored issues
show
Bug introduced by
Accessing dispatcher on the interface Micro\Base\IContainer suggest that you code against a concrete implementation. How about adding an instanceof check?

If you access a property on an interface, you most likely code against a concrete implementation of the interface.

Available Fixes

  1. Adding an additional type check:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeInterface $object) {
        if ($object instanceof SomeClass) {
            $a = $object->a;
        }
    }
    
  2. Changing the type hint:

    interface SomeInterface { }
    class SomeClass implements SomeInterface {
        public $a;
    }
    
    function someFunction(SomeClass $object) {
        $a = $object->a;
    }
    
Loading history...
360
    }
361
362
    /**
363
     * Get status of debug
364
     *
365
     * @access public
366
     *
367
     * @return bool
368
     */
369
    public function isDebug()
370
    {
371
        return $this->debug;
372
    }
373
374
    /**
375
     * Get components container
376
     *
377
     * @access public
378
     *
379
     * @return IContainer
380
     */
381
    public function getContainer()
382
    {
383
        return $this->container;
384
    }
385
386
    /**
387
     * Get character set
388
     *
389
     * @access public
390
     *
391
     * @return string
392
     */
393
    public function getCharset()
394
    {
395
        return 'UTF-8';
396
    }
397
398
    /**
399
     * Get logs directory
400
     *
401
     * @return string
402
     */
403
    public function getLogDir()
404
    {
405
        return $this->getAppDir() . '/logs';
406
    }
407
408
    /**
409
     * Get cache directory
410
     *
411
     * @return string
412
     */
413
    public function getCacheDir()
414
    {
415
        return $this->getAppDir() . '/cache/' . $this->getEnvironment();
416
    }
417
418
    /**
419
     * Get environment name
420
     *
421
     * @access public
422
     *
423
     * @return string
424
     */
425
    public function getEnvironment()
426
    {
427
        return $this->environment;
428
    }
429
}
430