Completed
Push — develop ( 37deef...f45442 )
by Jaap
05:54
created

phpDocumentor/Descriptor/PropertyDescriptor.php (1 issue)

strict.coding_against_concrete_implementation

Bug Minor

Upgrade to new PHP Analysis Engine

These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more

1
<?php
2
/**
3
 * phpDocumentor
4
 *
5
 * PHP Version 5.3
6
 *
7
 * @copyright 2010-2014 Mike van Riel / Naenius (http://www.naenius.com)
8
 * @license   http://www.opensource.org/licenses/mit-license.php MIT
9
 * @link      http://phpdoc.org
10
 */
11
12
namespace phpDocumentor\Descriptor;
13
14
use phpDocumentor\Descriptor\Tag\VarDescriptor;
15
use phpDocumentor\Reflection\Type;
16
17
/**
18
 * Descriptor representing a property.
19
 */
20
class PropertyDescriptor extends DescriptorAbstract implements
21
    Interfaces\PropertyInterface,
22
    Interfaces\VisibilityInterface
23
{
24
    /** @var ClassDescriptor|TraitDescriptor $parent */
25
    protected $parent;
26
27
    /** @var string[]|null $types */
28
    protected $types;
29
30
    /** @var string $default */
31
    protected $default;
32
33
    /** @var bool $static */
34
    protected $static = false;
35
36
    /** @var string $visibility */
37
    protected $visibility = 'public';
38
39
    /**
40
     * @param ClassDescriptor|TraitDescriptor $parent
41
     */
42 2
    public function setParent($parent)
43
    {
44 2
        $this->setFullyQualifiedStructuralElementName(
45 2
            $parent->getFullyQualifiedStructuralElementName() . '::$' . $this->getName()
46
        );
47
48 2
        $this->parent = $parent;
49 2
    }
50
51
    /**
52
     * @return ClassDescriptor|TraitDescriptor
53
     */
54 1
    public function getParent()
55
    {
56 1
        return $this->parent;
57
    }
58
59
    /**
60
     * {@inheritDoc}
61
     */
62 1
    public function setDefault($default)
63
    {
64 1
        $this->default = $default;
65 1
    }
66
67
    /**
68
     * {@inheritDoc}
69
     */
70 1
    public function getDefault()
71
    {
72 1
        return $this->default;
73
    }
74
75
    /**
76
     * {@inheritDoc}
77
     */
78 1
    public function setStatic($static)
79
    {
80 1
        $this->static = $static;
81 1
    }
82
83
    /**
84
     * {@inheritDoc}
85
     */
86 1
    public function isStatic()
87
    {
88 1
        return $this->static;
89
    }
90
91
    /**
92
     * {@inheritDoc}
93
     */
94 1
    public function setTypes(Type $types)
95
    {
96 1
        $this->types = $types;
97 1
    }
98
99
    /**
100
     * {@inheritDoc}
101
     */
102 2
    public function getTypes()
103
    {
104 2
        if (!$this->types) {
105 2
            $this->types = new Collection();
106
107
            /** @var VarDescriptor $var */
108 2
            $var = $this->getVar()->getIterator()->current();
0 ignored issues
show
It seems like you code against a concrete implementation and not the interface Traversable as the method current() does only exist in the following implementations of said interface: APCUIterator, AppendIterator, ArrayIterator, Behat\Behat\Gherkin\Spec...ion\LazyFeatureIterator, Behat\Testwork\Specifica...edSpecificationIterator, Behat\Testwork\Specifica...oSpecificationsIterator, Behat\Testwork\Specifica...cificationArrayIterator, CachingIterator, CallbackFilterIterator, CoreTestIterator, DirectoryIterator, EmptyIterator, File_Iterator, FilesystemIterator, FilterIterator, Generator, GlobIterator, HttpMessage, HttpRequestPool, Imagick, ImagickPixelIterator, InfiniteIterator, Issue523, IteratorIterator, LimitIterator, MongoCommandCursor, MongoCursor, MongoGridFSCursor, MultipleIterator, NoRewindIterator, PHPUnit\Framework\TestSuiteIterator, PHPUnit\Runner\Filter\ExcludeGroupFilterIterator, PHPUnit\Runner\Filter\GroupFilterIterator, PHPUnit\Runner\Filter\IncludeGroupFilterIterator, PHPUnit\Runner\Filter\NameFilterIterator, PHP_Token_Stream, ParentIterator, Phar, PharData, PharIo\Manifest\AuthorCollectionIterator, PharIo\Manifest\AuthorElementCollection, PharIo\Manifest\BundledComponentCollectionIterator, PharIo\Manifest\ComponentElementCollection, PharIo\Manifest\ElementCollection, PharIo\Manifest\ExtElementCollection, PharIo\Manifest\RequirementCollectionIterator, Pimple\ServiceIterator, RecursiveArrayIterator, RecursiveCachingIterator, RecursiveCallbackFilterIterator, RecursiveDirectoryIterator, RecursiveFilterIterator, RecursiveIteratorIterator, RecursiveRegexIterator, RecursiveTreeIterator, RegexIterator, SQLiteResult, SebastianBergmann\CodeCoverage\Node\Iterator, SimpleXMLIterator, SplDoublyLinkedList, SplFileObject, SplFixedArray, SplHeap, SplMaxHeap, SplMinHeap, SplObjectStorage, SplPriorityQueue, SplQueue, SplStack, SplTempFileObject, Symfony\Component\Finder...or\CustomFilterIterator, Symfony\Component\Finder...DateRangeFilterIterator, Symfony\Component\Finder...epthRangeFilterIterator, Symfony\Component\Finder...DirectoryFilterIterator, Symfony\Component\Finder...rator\FilePathsIterator, Symfony\Component\Finder...\FileTypeFilterIterator, Symfony\Component\Finder...lecontentFilterIterator, Symfony\Component\Finder...\FilenameFilterIterator, Symfony\Component\Finder\Iterator\FilterIterator, Symfony\Component\Finder...tiplePcreFilterIterator, Symfony\Component\Finder...ator\PathFilterIterator, Symfony\Component\Finder...ursiveDirectoryIterator, Symfony\Component\Finder...SizeRangeFilterIterator, Symfony\Component\Finder...rator\InnerNameIterator, Symfony\Component\Finder...rator\InnerSizeIterator, Symfony\Component\Finder...rator\InnerTypeIterator, Symfony\Component\Finder\Tests\Iterator\Iterator, Symfony\Component\Finder...or\MockFileListIterator, Symfony\Component\Finder...tiplePcreFilterIterator, TestIterator, TestIterator2, TheSeer\Tokenizer\TokenCollection, TwigTestFoo, Twig\Util\TemplateDirIterator, Twig_Util_TemplateDirIterator, Zend\Cache\Storage\Adapter\ApcIterator, Zend\Cache\Storage\Adapter\ApcuIterator, Zend\Cache\Storage\Adapter\DbaIterator, Zend\Cache\Storage\Adapter\FilesystemIterator, Zend\Cache\Storage\Adapter\KeyListIterator, Zend\Config\Config, Zend\EventManager\ResponseCollection, Zend\Hydrator\Iterator\HydratingArrayIterator, Zend\Hydrator\Iterator\HydratingIteratorIterator, Zend\Stdlib\FastPriorityQueue, Zend\Stdlib\Hydrator\Ite...\HydratingArrayIterator, Zend\Stdlib\Hydrator\Ite...dratingIteratorIterator, Zend\Stdlib\PriorityList, Zend\Stdlib\SplPriorityQueue, Zend\Stdlib\SplQueue, Zend\Stdlib\SplStack, ezcBaseAutoloadOptions, ezcBaseOptions, ezcBaseTestOptions, ezcDocumentBBCodeOptions, ezcDocumentConverterOptions, ezcDocumentDocbookOptions, ezcDocumentDocbookToEzXmlConverterOptions, ezcDocumentDocbookToHtmlConverterOptions, ezcDocumentDocbookToHtmlXsltConverterOptions, ezcDocumentDocbookToOdtConverterOptions, ezcDocumentDocbookToRstConverterOptions, ezcDocumentDocbookToWikiConverterOptions, ezcDocumentEzXmlOptions, ezcDocumentEzXmlToDocbookConverterOptions, ezcDocumentHtmlConverterOptions, ezcDocumentOdtOptions, ezcDocumentOptions, ezcDocumentParserOptions, ezcDocumentPdfFooterOptions, ezcDocumentPdfOptions, ezcDocumentRstOptions, ezcDocumentWikiOptions, ezcDocumentXhtmlOptions, ezcDocumentXmlOptions, ezcDocumentXsltConverterOptions, org\bovigo\vfs\vfsStreamContainerIterator, phpDocumentor\Compiler\Compiler, phpDocumentor\Reflection...y\ClassConstantIterator, phpDocumentor\Reflection...actory\PropertyIterator, phpDocumentor\Transformer\Router\Queue, phpDocumentor\Transformer\Template.

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...
109 2
            if ($var) {
110 1
                $this->types = $var->getTypes();
111
            }
112
        }
113
114 2
        return $this->types;
115
    }
116
117
    /**
118
     * {@inheritDoc}
119
     */
120 1
    public function setVisibility($visibility)
121
    {
122 1
        $this->visibility = $visibility;
123 1
    }
124
125
    /**
126
     * {@inheritDoc}
127
     */
128 1
    public function getVisibility()
129
    {
130 1
        return $this->visibility;
131
    }
132
133
    /**
134
     * @return Collection
135
     */
136 2
    public function getVar()
137
    {
138
        /** @var Collection $var */
139 2
        $var = $this->getTags()->get('var', new Collection());
140 2
        if ($var->count() != 0) {
141 1
            return $var;
142
        }
143
144 2
        $inheritedElement = $this->getInheritedElement();
145 2
        if ($inheritedElement) {
146 1
            return $inheritedElement->getVar();
147
        }
148
149 1
        return new Collection();
150
    }
151
152
    /**
153
     * Returns the file associated with the parent class or trait.
154
     *
155
     * @return FileDescriptor
156
     */
157 1
    public function getFile()
158
    {
159 1
        return $this->getParent()->getFile();
160
    }
161
162
    /**
163
     * Returns the property from which this one should inherit, if any.
164
     *
165
     * @return PropertyDescriptor|null
166
     */
167 2
    public function getInheritedElement()
168
    {
169
        /** @var ClassDescriptor|InterfaceDescriptor|null $associatedClass */
170 2
        $associatedClass = $this->getParent();
171
172 2
        if (($associatedClass instanceof ClassDescriptor || $associatedClass instanceof InterfaceDescriptor)
173 1
            && ($associatedClass->getParent() instanceof ClassDescriptor
174 2
                || $associatedClass->getParent() instanceof InterfaceDescriptor
175
            )
176
        ) {
177
            /** @var ClassDescriptor|InterfaceDescriptor $parentClass */
178 1
            $parentClass = $associatedClass->getParent();
179
180 1
            return $parentClass->getProperties()->get($this->getName());
181
        }
182
183 1
        return null;
184
    }
185
}
186