TypeDocblockGeneratorPart::getType()
last analyzed

Size

Total Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 1
ccs 0
cts 0
cp 0
nc 1
1
<?php
2
declare(strict_types=1);
3
4
namespace gossi\codegen\model\parts;
5
6
use gossi\docblock\Docblock;
7
use gossi\docblock\tags\AbstractTag;
8
9
/**
10
 * Type docblock generator part
11
 *
12
 * For all models that have a type and need docblock tag generated from it
13
 *
14
 * @author Thomas Gossmann
15
 */
16
trait TypeDocblockGeneratorPart {
17
18
	/**
19
	 * Returns the docblock
20
	 *
21
	 * @return Docblock
22
	 */
23
	abstract protected function getDocblock(): Docblock;
24
25
	/**
26
	 * Returns the type
27
	 *
28
	 * @return string
29
	 */
30
	abstract public function getType(): ?string;
31
32
	/**
33
	 * Returns the type description
34
	 *
35
	 * @return string
36
	 */
37
	abstract public function getTypeDescription(): ?string;
38
39
	/**
40
	 * Generates a type tag (return or var) but checks if one exists and updates this one
41
	 *
42
	 * @param AbstractTag $tag
43
	 */
44 16
	protected function generateTypeTag(AbstractTag $tag) {
45 16
		$docblock = $this->getDocblock();
46 16
		$type = $this->getType();
47
48 16
		if (!empty($type)) {
49
50
			// try to find tag at first and update
51 9
			$tags = $docblock->getTags($tag->getTagName());
52 9
			if ($tags->size() > 0) {
53 1
				$ttag = $tags->get(0);
54 1
				$ttag->setType($this->getType());
55 1
				$ttag->setDescription($this->getTypeDescription());
56
			}
57
58
			// ... anyway create and append
59
			else {
60 8
				$docblock->appendTag($tag
0 ignored issues
show
Bug introduced by
It seems like you code against a specific sub-type and not the parent class gossi\docblock\tags\AbstractTag as the method setType() does only exist in the following sub-classes of gossi\docblock\tags\AbstractTag: gossi\docblock\tags\AbstractTypeTag, gossi\docblock\tags\AbstractVarTypeTag, gossi\docblock\tags\MethodTag, gossi\docblock\tags\ParamTag, gossi\docblock\tags\PropertyReadTag, gossi\docblock\tags\PropertyTag, gossi\docblock\tags\PropertyWriteTag, gossi\docblock\tags\ReturnTag, gossi\docblock\tags\ThrowsTag, gossi\docblock\tags\TypeTag, gossi\docblock\tags\VarTag. 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...
61 8
					->setType($this->getType())
62 8
					->setDescription($this->getTypeDescription())
63
				);
64
			}
65
		}
66 16
	}
67
}
68