Completed
Push — master ( c39dfb...499778 )
by Emily
02:18
created

ReflectorFactory::setInt()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 3
cp 0
rs 10
c 0
b 0
f 0
cc 1
eloc 2
nc 1
nop 2
crap 2
1
<?php
2
/**
3
 * This file is part of the Composite Utils package.
4
 *
5
 * (c) Emily Shepherd <[email protected]>
6
 *
7
 * For the full copyright and license information, please view the
8
 * LICENSE.md file that was distributed with this source code.
9
 *
10
 * @package spaark/composite-utils
11
 * @author Emily Shepherd <[email protected]>
12
 * @license MIT
13
 */
14
15
namespace Spaark\CompositeUtils\Factory\Reflection;
16
17
use Spaark\CompositeUtils\Factory\BaseFactory;
18
use Spaark\CompositeUtils\Service\RawPropertyAccessor;
19
use Spaark\CompositeUtils\Model\Reflection\Reflector as SpaarkReflector;
20
use \Reflector as PHPNativeReflector;
21
22
/**
23
 * Abstract class for specific Reflection factories to extend
24
 */
25
abstract class ReflectorFactory extends BaseFactory
26
{
27
    const REFLECTION_OBJECT = null;
28
29
    /**
30
     * @var PHPNativeReflector
31
     */
32
    protected $reflector;
33
34
    /**
35
     * @var RawPropertyAccessor
36
     */
37
    protected $accessor;
38
39
    /**
40
     * @var SpaarkReflector
41
     */
42
    protected $object;
43
44
    /**
45
     * Creates a new ReflectorFactory using the provided native PHP
46
     * reflector as a basis
47
     *
48
     * @param PHPNativeReflector $reflector The reflector used to
49
     *     parse the item
50
     */
51 24
    public function __construct(PHPNativeReflector $reflector)
52
    {
53 24
        $class = static::REFLECTION_OBJECT;
54
55 24
        $this->object = new $class();
56 24
        $this->accessor = new RawPropertyAccessor($this->object);
57 24
        $this->reflector = $reflector;
58 24
    }
59
60
    /**
61
     * Parses the docblock comment for this item and searches for
62
     * annotations
63
     */
64 24
    protected function parseDocComment(array $acceptedParams)
65
    {
66 24
        preg_match_all
67
        (
68
              '/^'
69
            .     '[ \t]*\*[ \t]*'
70
            .     '@([a-zA-Z]+)'
71
            .     '(.*)'
72 24
            . '$/m',
73 24
            $this->reflector->getDocComment(),
0 ignored issues
show
Bug introduced by
It seems like you code against a concrete implementation and not the interface Reflector as the method getDocComment() does only exist in the following implementations of said interface: ReflectionClass, ReflectionFunction, ReflectionFunctionAbstract, ReflectionMethod, ReflectionObject, ReflectionProperty.

Let’s take a look at an example:

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

class MyUser implements 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 implementation 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 interface:

    interface User
    {
        /** @return string */
        public function getPassword();
    
        /** @return string */
        public function getDisplayName();
    }
    
Loading history...
74
            $matches
75
        );
76
77 24
        foreach ($matches[0] as $key => $value)
78
        {
79 24
            $name = strtolower($matches[1][$key]);
80 24
            $value = trim($matches[2][$key]);
81
82 24
            if (isset($acceptedParams[$name]))
83
            {
84 24
                call_user_func
85
                (
86 24
                    array($this, $acceptedParams[$name]),
87
                    $name, $value
88
                );
89
            }
90
        }
91 24
    }
92
93
    /**
94
     * Sets an annotation which has a boolean value
95
     *
96
     * @param string $name The name of the annotation
97
     * @param string $value The value of the annotation
98
     */
99 22
    protected function setBool($name, $value)
100
    {
101 22
        switch(strtolower($value))
102
        {
103 22
            case '':
104 21
            case 'true':
105 22
                $value = true;
106 22
                break;
107
108 21
            case 'false':
109 21
                $value = false;
110 21
                break;
111
112
            default:
113 21
                $value = (boolean)$value;
114
        }
115
116 22
        $this->accessor->setRawValue($name, $value);
117 22
    }
118
}
119
120