Subversion-Projekte lars-tiefland.laravel_shop

Revision

Zur aktuellen Revision | Details | Letzte Änderung | Log anzeigen | RSS feed

Revision Autor Zeilennr. Zeile
148 lars 1
<?php
2
 
3
/*
4
 * This file is part of Psy Shell.
5
 *
6
 * (c) 2012-2022 Justin Hileman
7
 *
8
 * For the full copyright and license information, please view the LICENSE
9
 * file that was distributed with this source code.
10
 */
11
 
12
namespace Psy\CodeCleaner;
13
 
14
use PhpParser\Node;
15
use PhpParser\Node\Expr\ConstFetch;
16
use PhpParser\Node\Expr\FuncCall;
17
use PhpParser\Node\Name;
18
use PhpParser\Node\Stmt\Class_;
19
use PhpParser\Node\Stmt\Trait_;
20
use PhpParser\Node\VariadicPlaceholder;
21
use Psy\Exception\ErrorException;
22
 
23
/**
24
 * The called class pass throws warnings for get_class() and get_called_class()
25
 * outside a class context.
26
 */
27
class CalledClassPass extends CodeCleanerPass
28
{
29
    private $inClass;
30
 
31
    /**
32
     * @param array $nodes
33
     *
34
     * @return Node[]|null Array of nodes
35
     */
36
    public function beforeTraverse(array $nodes)
37
    {
38
        $this->inClass = false;
39
    }
40
 
41
    /**
42
     * @throws ErrorException if get_class or get_called_class is called without an object from outside a class
43
     *
44
     * @param Node $node
45
     *
46
     * @return int|Node|null Replacement node (or special return value)
47
     */
48
    public function enterNode(Node $node)
49
    {
50
        if ($node instanceof Class_ || $node instanceof Trait_) {
51
            $this->inClass = true;
52
        } elseif ($node instanceof FuncCall && !$this->inClass) {
53
            // We'll give any args at all (besides null) a pass.
54
            // Technically we should be checking whether the args are objects, but this will do for now.
55
            //
56
            // @todo switch this to actually validate args when we get context-aware code cleaner passes.
57
            if (!empty($node->args) && !$this->isNull($node->args[0])) {
58
                return;
59
            }
60
 
61
            // We'll ignore name expressions as well (things like `$foo()`)
62
            if (!($node->name instanceof Name)) {
63
                return;
64
            }
65
 
66
            $name = \strtolower($node->name);
67
            if (\in_array($name, ['get_class', 'get_called_class'])) {
68
                $msg = \sprintf('%s() called without object from outside a class', $name);
69
                throw new ErrorException($msg, 0, \E_USER_WARNING, null, $node->getLine());
70
            }
71
        }
72
    }
73
 
74
    /**
75
     * @param Node $node
76
     *
77
     * @return int|Node|Node[]|null Replacement node (or special return value)
78
     */
79
    public function leaveNode(Node $node)
80
    {
81
        if ($node instanceof Class_) {
82
            $this->inClass = false;
83
        }
84
    }
85
 
86
    private function isNull(Node $node): bool
87
    {
88
        if ($node instanceof VariadicPlaceholder) {
89
            return false;
90
        }
91
 
92
        return $node->value instanceof ConstFetch && \strtolower($node->value->name) === 'null';
93
    }
94
}