annotate vendor/psy/psysh/src/CodeCleaner/ValidConstructorPass.php @ 19:fa3358dc1485 tip

Add ndrum files
author Chris Cannam
date Wed, 28 Aug 2019 13:14:47 +0100
parents 129ea1e6d783
children
rev   line source
Chris@13 1 <?php
Chris@13 2
Chris@13 3 /*
Chris@13 4 * This file is part of Psy Shell.
Chris@13 5 *
Chris@13 6 * (c) 2012-2018 Justin Hileman
Chris@13 7 *
Chris@13 8 * For the full copyright and license information, please view the LICENSE
Chris@13 9 * file that was distributed with this source code.
Chris@13 10 */
Chris@13 11
Chris@13 12 namespace Psy\CodeCleaner;
Chris@13 13
Chris@13 14 use PhpParser\Node;
Chris@13 15 use PhpParser\Node\Identifier;
Chris@13 16 use PhpParser\Node\Stmt\Class_;
Chris@13 17 use PhpParser\Node\Stmt\ClassMethod;
Chris@13 18 use PhpParser\Node\Stmt\Namespace_;
Chris@13 19 use Psy\Exception\FatalErrorException;
Chris@13 20
Chris@13 21 /**
Chris@13 22 * Validate that the constructor method is not static, and does not have a
Chris@13 23 * return type.
Chris@13 24 *
Chris@13 25 * Checks both explicit __construct methods as well as old-style constructor
Chris@13 26 * methods with the same name as the class (for non-namespaced classes).
Chris@13 27 *
Chris@13 28 * As of PHP 5.3.3, methods with the same name as the last element of a
Chris@13 29 * namespaced class name will no longer be treated as constructor. This change
Chris@13 30 * doesn't affect non-namespaced classes.
Chris@13 31 *
Chris@13 32 * @author Martin HasoĊˆ <martin.hason@gmail.com>
Chris@13 33 */
Chris@13 34 class ValidConstructorPass extends CodeCleanerPass
Chris@13 35 {
Chris@13 36 private $namespace;
Chris@13 37
Chris@13 38 public function beforeTraverse(array $nodes)
Chris@13 39 {
Chris@13 40 $this->namespace = [];
Chris@13 41 }
Chris@13 42
Chris@13 43 /**
Chris@13 44 * Validate that the constructor is not static and does not have a return type.
Chris@13 45 *
Chris@13 46 * @throws FatalErrorException the constructor function is static
Chris@13 47 * @throws FatalErrorException the constructor function has a return type
Chris@13 48 *
Chris@13 49 * @param Node $node
Chris@13 50 */
Chris@13 51 public function enterNode(Node $node)
Chris@13 52 {
Chris@13 53 if ($node instanceof Namespace_) {
Chris@13 54 $this->namespace = isset($node->name) ? $node->name->parts : [];
Chris@13 55 } elseif ($node instanceof Class_) {
Chris@13 56 $constructor = null;
Chris@13 57 foreach ($node->stmts as $stmt) {
Chris@13 58 if ($stmt instanceof ClassMethod) {
Chris@13 59 // If we find a new-style constructor, no need to look for the old-style
Chris@17 60 if ('__construct' === \strtolower($stmt->name)) {
Chris@13 61 $this->validateConstructor($stmt, $node);
Chris@13 62
Chris@13 63 return;
Chris@13 64 }
Chris@13 65
Chris@13 66 // We found a possible old-style constructor (unless there is also a __construct method)
Chris@17 67 if (empty($this->namespace) && \strtolower($node->name) === \strtolower($stmt->name)) {
Chris@13 68 $constructor = $stmt;
Chris@13 69 }
Chris@13 70 }
Chris@13 71 }
Chris@13 72
Chris@13 73 if ($constructor) {
Chris@13 74 $this->validateConstructor($constructor, $node);
Chris@13 75 }
Chris@13 76 }
Chris@13 77 }
Chris@13 78
Chris@13 79 /**
Chris@13 80 * @throws FatalErrorException the constructor function is static
Chris@13 81 * @throws FatalErrorException the constructor function has a return type
Chris@13 82 *
Chris@13 83 * @param Node $constructor
Chris@13 84 * @param Node $classNode
Chris@13 85 */
Chris@13 86 private function validateConstructor(Node $constructor, Node $classNode)
Chris@13 87 {
Chris@13 88 if ($constructor->isStatic()) {
Chris@13 89 // For PHP Parser 4.x
Chris@13 90 $className = $classNode->name instanceof Identifier ? $classNode->name->toString() : $classNode->name;
Chris@13 91
Chris@17 92 $msg = \sprintf(
Chris@13 93 'Constructor %s::%s() cannot be static',
Chris@17 94 \implode('\\', \array_merge($this->namespace, (array) $className)),
Chris@13 95 $constructor->name
Chris@13 96 );
Chris@13 97 throw new FatalErrorException($msg, 0, E_ERROR, null, $classNode->getLine());
Chris@13 98 }
Chris@13 99
Chris@17 100 if (\method_exists($constructor, 'getReturnType') && $constructor->getReturnType()) {
Chris@13 101 // For PHP Parser 4.x
Chris@13 102 $className = $classNode->name instanceof Identifier ? $classNode->name->toString() : $classNode->name;
Chris@13 103
Chris@17 104 $msg = \sprintf(
Chris@13 105 'Constructor %s::%s() cannot declare a return type',
Chris@17 106 \implode('\\', \array_merge($this->namespace, (array) $className)),
Chris@13 107 $constructor->name
Chris@13 108 );
Chris@13 109 throw new FatalErrorException($msg, 0, E_ERROR, null, $classNode->getLine());
Chris@13 110 }
Chris@13 111 }
Chris@13 112 }