We read every piece of feedback, and take your input very seriously.
To see all available qualifiers, see our documentation.
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
最近在迁移一个 上古 项目到 laravel 中。我这边的做法是先用 rector 做一个整体初步的语法升级与 laravel 写法的替换,然后主要就是手动重写数据操作的部分。到目前为止除了应用到 rector 自带的规则外,还写了一些自定义的规则,其中有一个规范化命名风格的规则(RenameToPsrNameRector)适用于所有的 PHP 项目,所以在此分享出来。该规则主要是针对常量、变量、函数、类、属性、方法等命名进行统一的规范。其中,常量名遵循大写蛇形命名风格,函数名遵循小写蛇形命名风格,类名遵循大驼峰命名风格,变量名、属性名、方法名遵循小驼峰命名风格。
上古
<?php // lower snake -function functionName(){} -functionName(); -call_user_func('functionName'); -call_user_func_array('functionName'); -function_exists('functionName'); +function function_name(){} +\function_name(); +call_user_func('function_name'); +call_user_func_array('function_name'); +function_exists('function_name'); // ucfirst camel -class class_name{} -enum enum_name{} -enum Enum{case case_name;} -interface interface_name{} -trait trait_name{} -class Foo extends class_name implements interface_name{} -class_name::$property; -class_name::CONST; -class_name::method(); -enum Enum implements interface_name{} -use class_name; -use trait_name; -class_alias('class_name', 'alias_class_name'); -class_exists('class_name'); -class_implements('class_name'); -class_parents('class_name'); -class_uses('class_name'); -enum_exists('enum_name'); -get_class_methods('class_name'); -get_class_vars('class_name'); -get_parent_class('class_name'); -interface_exists('interface_name'); -is_subclass_of('class_name', 'parent_class_name'); -trait_exists('trait_name', true); +class ClassName{} +enum EnumName{} +enum Enum{case CaseName;} +interface InterfaceName{} +trait TraitName{} +class Foo extends \ClassName implements \InterfaceName{} +\ClassName::$property; +\ClassName::CONST; +\ClassName::method(); +enum Enum implements \InterfaceName{} +use ClassName; +use TraitName; +class_alias('ClassName', 'AliasClassName'); +class_exists('ClassName'); +class_implements('ClassName'); +class_parents('ClassName'); +class_uses('ClassName'); +enum_exists('EnumName'); +get_class_methods('ClassName'); +get_class_vars('ClassName'); +get_parent_class('ClassName'); +interface_exists('InterfaceName'); +is_subclass_of('ClassName', 'ParentClassName'); +trait_exists('TraitName', true); // upper snake -class Foo{public const constName = 'const';} -Foo::constName; -define('constName', 'const'); -defined('constName'); -constant('constName'); +class Foo{public const CONST_NAME = 'const';} +Foo::CONST_NAME; +define('CONST_NAME', 'const'); +defined('CONST_NAME'); +constant('CONST_NAME'); constant('Foo::constName'); -constName; +\CONST_NAME; // lcfirst camel -$var_name; -$object->method_name(); -$object->property_name; -call_user_method('method_name', $object); -call_user_method_array('method_name', $object); -class Foo{public $property_name;} -class Foo{public function method_name(){}} -class Foo{public int $property_name;} -Foo::$property_name; -Foo::method_name(); -method_exists($object, 'method_name'); -property_exists($object, 'property_name'); +$varName; +$object->methodName(); +$object->propertyName; +call_user_method('methodName', $object); +call_user_method_array('methodName', $object); +class Foo{public $propertyName;} +class Foo{public function methodName(){}} +class Foo{public int $propertyName;} +Foo::$propertyName; +Foo::methodName(); +method_exists($object, 'methodName'); +property_exists($object, 'propertyName');
<?php namespace App\Support\Rectors; use Illuminate\Support\Str; use PhpParser\Node; use Rector\Core\Contract\Rector\ConfigurableRectorInterface; use Rector\Core\Rector\AbstractRector; use RectorPrefix202305\Webmozart\Assert\Assert; use Symplify\RuleDocGenerator\ValueObject\CodeSample\ConfiguredCodeSample; use Symplify\RuleDocGenerator\ValueObject\RuleDefinition; class RenameToPsrNameRector extends AbstractRector implements ConfigurableRectorInterface { /** * @var array<string> */ protected $except = [ '*::*', 'class', 'false', 'null', 'self', 'static', 'stdClass', 'true', ]; public function getRuleDefinition(): RuleDefinition { return new RuleDefinition( 'Rename to psr name', [ new ConfiguredCodeSample( <<<'CODE_SAMPLE' // lower snake function functionName(){} functionName(); call_user_func('functionName'); call_user_func_array('functionName'); function_exists('functionName'); // ucfirst camel class class_name{} enum enum_name{} enum Enum{case case_name;} interface interface_name{} trait trait_name{} class Foo extends class_name implements interface_name{} class_name::$property; class_name::CONST; class_name::method(); enum Enum implements interface_name{} use class_name; use trait_name; class_alias('class_name', 'alias_class_name'); class_exists('class_name'); class_implements('class_name'); class_parents('class_name'); class_uses('class_name'); enum_exists('enum_name'); get_class_methods('class_name'); get_class_vars('class_name'); get_parent_class('class_name'); interface_exists('interface_name'); is_subclass_of('class_name', 'parent_class_name'); trait_exists('trait_name', true); // upper snake class Foo{public const constName = 'const';} Foo::constName; define('constName', 'const'); defined('constName'); constant('constName'); constant('Foo::constName'); constName; // lcfirst camel $var_name; $object->method_name(); $object->property_name; call_user_method('method_name', $object); call_user_method_array('method_name', $object); class Foo{public $property_name;} class Foo{public function method_name(){}} class Foo{public int $property_name;} Foo::$property_name; Foo::method_name(); method_exists($object, 'method_name'); property_exists($object, 'property_name'); CODE_SAMPLE , <<<'CODE_SAMPLE' // lower snake function function_name(){} function_name(); call_user_func('function_name'); call_user_func_array('function_name'); function_exists('function_name'); // ucfirst camel class ClassName{} enum EnumName{} enum Enum{case CaseName;} interface InterfaceName{} trait TraitName{} class Foo extends ClassName implements InterfaceName{} ClassName::$property; ClassName::CONST; ClassName::method(); enum Enum implements InterfaceName{} use ClassName; use TraitName; class_alias('ClassName', 'AliasClassName'); class_exists('ClassName'); class_implements('ClassName'); class_parents('ClassName'); class_uses('ClassName'); enum_exists('EnumName'); get_class_methods('ClassName'); get_class_vars('ClassName'); get_parent_class('ClassName'); interface_exists('InterfaceName'); is_subclass_of('ClassName', 'ParentClassName'); trait_exists('TraitName', true); // upper snake class Foo{public const CONST_NAME = 'const';} Foo::CONST_NAME; define('CONST_NAME', 'const'); defined('CONST_NAME'); constant('CONST_NAME'); constant('Foo::CONST_NAME'); CONST_NAME; // lcfirst camel $varName $object->methodName(); $object->propertyName; class Foo{public $propertyName;} class Foo{public function methodName(){}} class Foo{public int $propertyName;} Foo::$propertyName; Foo::methodName(); call_user_method('methodName', $object); call_user_method_array('methodName', $object); method_exists($object, 'methodName'); property_exists($object, 'propertyName'); CODE_SAMPLE , ['exceptName'] ), ]); } /** * {@inheritDoc} */ public function getNodeTypes(): array { return [ Node\Expr\FuncCall::class, Node\Expr\Variable::class, Node\Identifier::class, Node\Name::class, ]; } /** * @param Node\Expr\FuncCall|Node\Expr\Variable|Node\Identifier|Node\Name $node */ public function refactor(Node $node) { try { if ($this->shouldLowerSnakeName($node)) { return $this->rename($node, static fn (string $name): string => Str::lower(Str::snake($name))); } if ($this->shouldUcfirstCamelName($node)) { return $this->rename($node, static fn (string $name): string => Str::ucfirst(Str::camel($name))); } if ($this->shouldUpperSnakeName($node)) { return $this->rename($node, static fn (string $name): string => Str::upper(Str::snake($name))); } if ($this->shouldLcfirstCamelName($node)) { return $this->rename($node, static fn (string $name): string => Str::lcfirst(Str::camel($name))); } } catch (\RuntimeException $e) { // skip } return null; } /** * @param Node\Expr\FuncCall|Node\Expr\Variable|Node\Identifier|Node\Name $node */ protected function rename(Node $node, callable $renamer): Node { $renamer = fn (string $name): string => $renamer((function (string $name): string { if ($this->isMatches($name, $this->except)) { throw new \RuntimeException("The name[$name] is skipped."); } if (ctype_upper(preg_replace('/[^a-zA-Z]/', '', $name))) { return mb_strtolower($name, 'UTF-8'); } return $name; })($name)); if ($node instanceof Node\Name) { $node->parts[count($node->parts) - 1] = $renamer($node->parts[count($node->parts) - 1]); return $node; } if ( $this->isSubclasses($node, [ Node\Expr\Variable::class, Node\Identifier::class, ]) ) { $node->name = $renamer($node->name); return $node; } if ($node instanceof Node\Expr\FuncCall) { if ( $this->isNames($node, [ 'call_user_func', 'call_user_func_array', 'call_user_method', 'call_user_method_array', 'class_alias', 'class_exists', 'class_implements', 'class_parents', 'class_uses', 'constant', 'define', 'defined', 'enum_exists', 'function_exists', 'get_class_methods', 'get_class_vars', 'get_parent_class', 'interface_exists', 'is_subclass_of', 'trait_exists', ]) && $this->hasFuncCallIndexStringArg($node, 0) ) { $node->args[0]->value->value = $renamer($node->args[0]->value->value); } if ( $this->isNames($node, [ 'class_alias', 'is_subclass_of', 'method_exists', 'property_exists', ]) && $this->hasFuncCallIndexStringArg($node, 1) ) { $node->args[1]->value->value = $renamer($node->args[1]->value->value); } } return $node; } /** * @param Node\Expr\FuncCall|Node\Expr\Variable|Node\Identifier|Node\Name $node */ protected function shouldLowerSnakeName(Node $node): bool { $parent = $node->getAttribute('parent'); // function function_name(){} if ($node instanceof Node\Identifier && $parent instanceof Node\Stmt\Function_) { return true; } // function_name(); if ($node instanceof Node\Name && $parent instanceof Node\Expr\FuncCall) { return true; } if ( $node instanceof Node\Expr\FuncCall && $this->isNames($node, [ // call_user_func('function_name'); 'call_user_func', // call_user_func_array('function_name'); 'call_user_func_array', // function_exists('function_name'); 'function_exists', ]) && $this->hasFuncCallIndexStringArg($node, 0) ) { return true; } return false; } /** * @param Node\Expr\FuncCall|Node\Expr\Variable|Node\Identifier|Node\Name $node */ protected function shouldUcfirstCamelName(Node $node): bool { $parent = $node->getAttribute('parent'); if ( $node instanceof Node\Identifier && $this->isSubclasses($parent, [ // interface InterfaceName{} Node\Stmt\Interface_::class, // class ClassName{} Node\Stmt\Class_::class, // trait TraitName{} Node\Stmt\Trait_::class, // enum EnumName{} Node\Stmt\Enum_::class, // enum Enum{case CaseName;} Node\Stmt\EnumCase::class, ]) ) { return true; } if ( $node instanceof Node\Name && ! $this->isName($node, 'stdClass') && $this->isSubclasses($parent, [ // class Foo extends ClassName implements InterfaceName{} Node\Stmt\Class_::class, // enum Enum implements InterfaceName{} Node\Stmt\Enum_::class, // use ClassName; Node\Stmt\UseUse::class, // use TraitName; Node\Stmt\TraitUse::class, // ClassName::CONST; Node\Expr\ClassConstFetch::class, // ClassName::$property; Node\Expr\StaticPropertyFetch::class, // ClassName::method(); Node\Expr\StaticCall::class, ]) ) { return true; } if ($node instanceof Node\Expr\FuncCall) { if ( $this->isNames($node, [ // class_alias('ClassName', 'AliasClassName'); 'class_alias', // class_exists('ClassName'); 'class_exists', // class_implements('ClassName'); 'class_implements', // class_parents('ClassName'); 'class_parents', // class_uses('ClassName'); 'class_uses', // enum_exists('EnumName'); 'enum_exists', // get_class_methods('ClassName'); 'get_class_methods', // get_class_vars('ClassName'); 'get_class_vars', // get_parent_class('ClassName'); 'get_parent_class', // interface_exists('InterfaceName'); 'interface_exists', // is_subclass_of('ClassName', 'ParentClassName'); 'is_subclass_of', // trait_exists('TraitName', true); 'trait_exists', ]) && $this->hasFuncCallIndexStringArg($node, 0) ) { return true; } if ( $this->isNames($node, [ // class_alias('ClassName', 'AliasClassName'); 'class_alias', // is_subclass_of('ClassName', 'ParentClassName'); 'is_subclass_of', ]) && $this->hasFuncCallIndexStringArg($node, 1) ) { return true; } } return false; } /** * @param Node\Expr\FuncCall|Node\Expr\Variable|Node\Identifier|Node\Name $node */ protected function shouldUpperSnakeName(Node $node): bool { $parent = $node->getAttribute('parent'); if ( $node instanceof Node\Identifier && ! $this->isName($node, 'class') && $this->isSubclasses($parent, [ // class Foo{public const CONST_NAME = 'const';} Node\Const_::class, // Foo::CONST_NAME; Node\Expr\ClassConstFetch::class, ]) ) { return true; } if ( $node instanceof Node\Expr\FuncCall && $this->isNames($node, [ // define('CONST_NAME', 'const'); 'define', // defined('CONST_NAME'); 'defined', // constant('Foo::CONST_NAME'); 'constant', ]) && $this->hasFuncCallIndexStringArg($node, 0) ) { return true; } // CONST_NAME; if ( $node instanceof Node\Name && ! $this->isNames($node, ['null', 'true', 'false']) && $parent instanceof Node\Expr\ConstFetch ) { return true; } return false; } /** * @param Node\Expr\FuncCall|Node\Expr\Variable|Node\Identifier|Node\Name $node */ protected function shouldLcfirstCamelName(Node $node): bool { // $varName; if ($node instanceof Node\Expr\Variable && is_string($node->name)) { return true; } if ( $node instanceof Node\Identifier && $this->isSubclasses($node->getAttribute('parent'), [ // class Foo{public $propertyName;} Node\Stmt\Property::class, // class Foo{public int $propertyName;} Node\Stmt\PropertyProperty::class, // class Foo{public function methodName(){}} Node\Stmt\ClassMethod::class, // $object->propertyName; Node\Expr\PropertyFetch::class, // Foo::$propertyName; Node\Expr\StaticPropertyFetch::class, // $object->methodName(); Node\Expr\MethodCall::class, // Foo::methodName(); Node\Expr\StaticCall::class, ]) ) { return true; } if ($node instanceof Node\Expr\FuncCall) { if ( $this->isNames($node, [ // call_user_method('methodName', $object); 'call_user_method', // call_user_method_array('methodName', $object); 'call_user_method_array', ]) && $this->hasFuncCallIndexStringArg($node, 0) ) { return true; } if ( $this->isNames($node, [ // method_exists($object, 'methodName'); 'method_exists', // property_exists($object, 'propertyName'); 'property_exists', ]) && $this->hasFuncCallIndexStringArg($node, 1) ) { return true; } } return false; } protected function isSubclasses($object, array $classes): bool { if (! is_object($object)) { return false; } foreach ($classes as $class) { if ($object instanceof $class) { return true; } } return false; } /** * @param string $value * @param string|iterable<string> $patterns */ public function isMatches($value, $patterns): bool { $value = (string) $value; if (! is_iterable($patterns)) { $patterns = [$patterns]; } foreach ($patterns as $pattern) { $pattern = (string) $pattern; if ($pattern === $value) { return true; } $pattern = preg_quote($pattern, '#'); $pattern = str_replace('\*', '.*', $pattern); if (preg_match('#^'.$pattern.'\z#u', $value) === 1) { return true; } } return false; } protected function hasFuncCallIndexStringArg(Node\Expr\FuncCall $funcCall, int $index): bool { return isset($funcCall->args[$index]) && $funcCall->args[$index]->name === null && $funcCall->args[$index]->value instanceof Node\Scalar\String_; } protected function hasFuncCallNameStringArg(Node\Expr\FuncCall $funcCall, string $name): bool { foreach ($funcCall->args as $arg) { if ( $arg->name instanceof Node\Identifier && $arg->name->name === $name && $arg->value instanceof Node\Scalar\String_ ) { return true; } } return false; } public function configure(array $configuration): void { Assert::allStringNotEmpty($configuration); $this->except = [...$this->except, ...$configuration]; } }
rector 配置文件中配置该规则即可
<?php declare(strict_types=1); use Rector\Config\RectorConfig; return static function (RectorConfig $rectorConfig): void { ... $rectorConfig->ruleWithConfiguration(\App\Support\Rectors\RenameToPsrNameRector::class, [ 'exceptName', ]); ... };
The text was updated successfully, but these errors were encountered:
No branches or pull requests
统一规范化代码的命名风格
效果
规则(RenameToPsrNameRector)
使用
rector 配置文件中配置该规则即可
参考链接
原文链接
The text was updated successfully, but these errors were encountered: