Completed
Pull Request — master (#283)
by Enrico
04:27
created

Metadata::getDescription()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 2
CRAP Score 1

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 1
eloc 2
nc 1
nop 0
dl 0
loc 4
ccs 2
cts 2
cp 1
crap 1
rs 10
c 1
b 0
f 0
1
<?php
2
/**
3
 * @author Kévin Gomez https://github.com/K-Phoen <[email protected]>
4
 */
5
6
namespace PHPSA\Analyzer\Pass;
7
8
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
9
use Symfony\Component\Config\Definition\Builder\TreeBuilder;
10
11
/**
12
 * Describes an analyzer pass.
13
 */
14
class Metadata
15
{
16
    /** @var string */
17
    private $name;
18
19
    /** @var string|null */
20
    private $description;
21
22
    /** @var \Symfony\Component\Config\Definition\Builder\NodeDefinition */
23
    private $configuration;
24
25
    /** @var string|null */
26
    private $requiredPhpVersion;
27
28
    /**
29
     * @param string $name
30
     * @param string|null $description
31
     *
32
     * @return Metadata
33
     */
34 51
    public static function create($name, $description = null)
35
    {
36 51
        $treeBuilder = new TreeBuilder();
37
38 51
        $config = $treeBuilder->root($name)
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class Symfony\Component\Config...\Builder\NodeDefinition as the method canBeDisabled() does only exist in the following sub-classes of Symfony\Component\Config...\Builder\NodeDefinition: Symfony\Component\Config...der\ArrayNodeDefinition. 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...
39 51
            ->info($description)
40 51
            ->canBeDisabled()
41 51
        ;
42
43 51
        return new self($name, $config, $description);
44
    }
45
46
    /**
47
     * @param string $name
48
     * @param NodeDefinition $config
49
     * @param string|null $description
50
     */
51 51
    public function __construct($name, NodeDefinition $config, $description = null)
52
    {
53 51
        $this->name = $name;
54 51
        $this->configuration = $config;
55 51
        $this->description = $description;
56 51
    }
57
58
    /**
59
     * @return string
60
     */
61 50
    public function getName()
62
    {
63 50
        return $this->name;
64
    }
65
66
    /**
67
     * @return string|null
68
     */
69 1
    public function getDescription()
70
    {
71 1
        return $this->description;
72
    }
73
74
    /**
75
     * @param string $description
76
     */
77
    public function setDescription($description)
78
    {
79
        $this->description = $description;
80
    }
81
82
    /**
83
     * @return NodeDefinition
84
     */
85 50
    public function getConfiguration()
86
    {
87 50
        return $this->configuration;
88
    }
89
90
    /**
91
     * @return string|null
92
     */
93
    public function getRequiredPhpVersion()
94
    {
95
        return $this->requiredPhpVersion;
96
    }
97
98
    /**
99
     * @param string $requiredPhpVersion
100
     */
101 51
    public function setRequiredPhpVersion($requiredPhpVersion)
102
    {
103 51
        $this->requiredPhpVersion = $requiredPhpVersion;
104 51
    }
105
106
    /**
107
     * Tells if the current analyzer can be used with code written in a given PHP version.
108
     *
109
     * @param string $version
110
     *
111
     * @return bool
112
     */
113 49
    public function allowsPhpVersion($version)
114
    {
115 49
        return $this->requiredPhpVersion === null || version_compare($version, $this->requiredPhpVersion, '>=');
116
    }
117
}
118