Completed
Push — master ( c4d2d4...eae51e )
by Alexander
9s
created

ReflectionType::__construct()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 6
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 5
CRAP Score 1

Importance

Changes 0
Metric Value
dl 0
loc 6
ccs 5
cts 5
cp 1
rs 9.4285
c 0
b 0
f 0
cc 1
eloc 4
nc 1
nop 3
crap 1
1
<?php
2
/**
3
 * Parser Reflection API
4
 *
5
 * @copyright Copyright 2015, Lisachenko Alexander <[email protected]>
6
 *
7
 * This source file is subject to the license that is bundled
8
 * with this source code in the file LICENSE.
9
 */
10
11
namespace Go\ParserReflection;
12
13
use ReflectionType as BaseReflectionType;
14
15
/**
16
 * ReflectionType implementation
17
 */
18
class ReflectionType extends BaseReflectionType
19
{
20
    /**
21
     * If type allows null or not
22
     *
23
     * @var boolean
24
     */
25
    private $allowsNull;
26
27
    /**
28
     * Is type built-in or not
29
     *
30
     * @var
31
     */
32
    private $isBuiltin;
33
34
    /**
35
     * @var string Type name
36
     */
37
    private $type;
38
39
    /**
40
     * Initializes reflection data
41
     */
42 31
    public function __construct($type, $allowsNull, $isBuiltin)
43
    {
44 31
        $this->type       = $type;
45 31
        $this->allowsNull = $allowsNull;
46 31
        $this->isBuiltin  = $isBuiltin;
47 31
    }
48
49
    /**
50
     * @inheritDoc
51
     */
52 31
    public function allowsNull()
53
    {
54 31
        return $this->allowsNull;
55
    }
56
57
    /**
58
     * @inheritDoc
59
     */
60 2
    public function isBuiltin()
61
    {
62 2
        return $this->isBuiltin;
63
    }
64
65
    /**
66
     * @inheritDoc
67
     */
68 2
    public function __toString()
69
    {
70 2
        return $this->type;
71
    }
72
73
    /**
74
     * PHP reflection has it's own rules, so 'int' type will be displayed as 'integer', etc...
75
     *
76
     * @see https://3v4l.org/nZFiT
77
     *
78
     * @param ReflectionType $type Type to display
79
     *
80
     * @return string
81
     */
82 29
    public static function convertToDisplayType(\ReflectionType $type)
83
    {
84 29
        static $typeMap = [
85
            'int'  => 'integer',
86
            'bool' => 'boolean'
87
        ];
88 29
        $displayType = $type->type;
0 ignored issues
show
Bug introduced by Alexander Lisachenko
The property type does not seem to exist in ReflectionType.

An attempt at access to an undefined property has been detected. This may either be a typographical error or the property has been renamed but there are still references to its old name.

If you really want to allow access to undefined properties, you can define magic methods to allow access. See the php core documentation on Overloading.

Loading history...
89 29
        if (isset($typeMap[$displayType])) {
90 11
            $displayType = $typeMap[$displayType];
91
        }
92
93 29
        $displayType = ltrim($displayType, '\\');
94
95 29
        if ($type->allowsNull()) {
0 ignored issues
show
Bug introduced by Alexander Lisachenko
It seems like you code against a specific sub-type and not the parent class ReflectionType as the method allowsNull() does only exist in the following sub-classes of ReflectionType: Go\ParserReflection\ReflectionType. Maybe you want to instanceof check for one of these explicitly?

Let’s take a look at an example:

abstract class User
{
    /** @return string */
    abstract public function getPassword();
}

class MyUser extends User
{
    public function getPassword()
    {
        // return something
    }

    public function getDisplayName()
    {
        // return some name.
    }
}

class AuthSystem
{
    public function authenticate(User $user)
    {
        $this->logger->info(sprintf('Authenticating %s.', $user->getDisplayName()));
        // do something.
    }
}

In the above example, the authenticate() method works fine as long as you just pass instances of MyUser. However, if you now also want to pass a different sub-classes of User which does not have a getDisplayName() method, the code will break.

Available Fixes

  1. Change the type-hint for the parameter:

    class AuthSystem
    {
        public function authenticate(MyUser $user) { /* ... */ }
    }
    
  2. Add an additional type-check:

    class AuthSystem
    {
        public function authenticate(User $user)
        {
            if ($user instanceof MyUser) {
                $this->logger->info(/** ... */);
            }
    
            // or alternatively
            if ( ! $user instanceof MyUser) {
                throw new \LogicException(
                    '$user must be an instance of MyUser, '
                   .'other instances are not supported.'
                );
            }
    
        }
    }
    
Note: PHP Analyzer uses reverse abstract interpretation to narrow down the types inside the if block in such a case.
  1. Add the method to the parent class:

    abstract class User
    {
        /** @return string */
        abstract public function getPassword();
    
        /** @return string */
        abstract public function getDisplayName();
    }
    
Loading history...
96 13
            $displayType .= ' or NULL';
97
        }
98
99 29
        return $displayType;
100
    }
101
}
102