• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

voku / Simple-PHP-Code-Parser / 24275564643

11 Apr 2026 05:21AM UTC coverage: 82.886% (+0.03%) from 82.857%
24275564643

Pull #79

github

web-flow
Merge 0c5e185e3 into 3fcaa1a81
Pull Request #79: Fix PHP 8 type resolution order and safe autoloading for newer syntax

98 of 128 new or added lines in 11 files covered. (76.56%)

12 existing lines in 5 files now uncovered.

1545 of 1864 relevant lines covered (82.89%)

45.52 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

71.43
/src/voku/SimplePhpParser/Model/PHPInterface.php
1
<?php
2

3
declare(strict_types=1);
4

5
namespace voku\SimplePhpParser\Model;
6

7
use PhpParser\Node\Stmt\Interface_;
8
use ReflectionClass;
9
use voku\SimplePhpParser\Parsers\Helper\Utils;
10

11
class PHPInterface extends BasePHPClass
12
{
13
    /**
14
     * @phpstan-var class-string
15
     */
16
    public string $name;
17

18
    /**
19
     * @var string[]
20
     *
21
     * @phpstan-var class-string[]
22
     */
23
    public array $parentInterfaces = [];
24

25
    /**
26
     * @param Interface_ $node
27
     * @param null       $dummy
28
     *
29
     * @return $this
30
     */
31
    public function readObjectFromPhpNode($node, $dummy = null): self
32
    {
33
        $this->prepareNode($node);
8✔
34

35
        $this->name = static::getFQN($node);
8✔
36

37
        // Extract PHP 8.0+ attributes
38
        if (!empty($node->attrGroups)) {
8✔
39
            $this->attributes = Utils::extractAttributesFromAstNode($node->attrGroups);
×
40
        }
41

42
        $interfaceExists = false;
8✔
43
        if (self::canAutoloadFromPhpNode($node)) {
8✔
44
            try {
45
                if (\interface_exists($this->name, true)) {
8✔
46
                    $interfaceExists = true;
8✔
47
                }
NEW
48
            } catch (\Throwable $e) {
×
49
                // nothing
50
            }
51
        }
52
        if ($interfaceExists) {
8✔
53
            $reflectionInterface = Utils::createClassReflectionInstance($this->name);
8✔
54
            $this->readObjectFromReflection($reflectionInterface);
8✔
55
        }
56

57
        $this->collectTags($node);
8✔
58

59
        foreach ($node->getMethods() as $method) {
8✔
60
            $methodNameTmp = $method->name->name;
8✔
61

62
            if (isset($this->methods[$methodNameTmp])) {
8✔
63
                $this->methods[$methodNameTmp] = $this->methods[$methodNameTmp]->readObjectFromPhpNode($method);
8✔
64
            } else {
65
                $this->methods[$methodNameTmp] = (new PHPMethod($this->parserContainer))->readObjectFromPhpNode($method);
×
66
            }
67

68
            if (!$this->methods[$methodNameTmp]->file) {
8✔
69
                $this->methods[$methodNameTmp]->file = $this->file;
×
70
            }
71
        }
72

73
        if (!empty($node->extends)) {
8✔
74
            /** @var class-string $interfaceExtended */
75
            $interfaceExtended = $node->extends[0]->toString();
×
76
            $this->parentInterfaces[] = $interfaceExtended;
×
77
        }
78

79
        return $this;
8✔
80
    }
81

82
    /**
83
     * @param ReflectionClass<object> $interface
84
     *
85
     * @return $this
86
     */
87
    public function readObjectFromReflection($interface): self
88
    {
89
        $this->name = $interface->getName();
31✔
90

91
        if (!$this->line) {
31✔
92
            $lineTmp = $interface->getStartLine();
23✔
93
            if ($lineTmp !== false) {
23✔
94
                $this->line = $lineTmp;
23✔
95
            }
96
        }
97

98
        $file = $interface->getFileName();
31✔
99
        if ($file) {
31✔
100
            $this->file = $file;
31✔
101
        }
102

103
        $this->is_final = $interface->isFinal();
31✔
104

105
        $this->is_abstract = $interface->isAbstract();
31✔
106

107
        $this->is_anonymous = $interface->isAnonymous();
31✔
108

109
        $this->is_cloneable = $interface->isCloneable();
31✔
110

111
        $this->is_instantiable = $interface->isInstantiable();
31✔
112

113
        $this->is_iterable = $interface->isIterable();
31✔
114

115
        // Extract PHP 8.0+ attributes
116
        $this->attributes = Utils::extractAttributesFromReflection($interface);
31✔
117

118
        foreach ($interface->getMethods() as $method) {
31✔
119
            $this->methods[$method->getName()] = (new PHPMethod($this->parserContainer))->readObjectFromReflection($method);
31✔
120
        }
121

122
        /** @var class-string[] $interfaceNames */
123
        $interfaceNames = $interface->getInterfaceNames();
31✔
124
        $this->parentInterfaces = $interfaceNames;
31✔
125

126
        foreach ($this->parentInterfaces as $parentInterface) {
31✔
127
            $interfaceExists = false;
×
128
            try {
129
                if (
130
                    !$this->parserContainer->getInterface($parentInterface)
×
131
                    &&
132
                    \interface_exists($parentInterface, true)
×
133
                ) {
134
                    $interfaceExists = true;
×
135
                }
136
            } catch (\Throwable $e) {
×
137
                // nothing
138
            }
139
            if ($interfaceExists) {
×
140
                $reflectionInterface = Utils::createClassReflectionInstance($parentInterface);
×
141
                $parentInterfaceNew = (new self($this->parserContainer))->readObjectFromReflection($reflectionInterface);
×
142
                $this->parserContainer->addInterface($parentInterfaceNew);
×
143
            }
144
        }
145

146
        foreach ($interface->getReflectionConstants() as $constant) {
31✔
147
            $this->constants[$constant->getName()] = (new PHPConst($this->parserContainer))->readObjectFromReflection($constant);
×
148
        }
149

150
        return $this;
31✔
151
    }
152
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc