1: <?php
2:
3: declare(strict_types=1);
4:
5: /**
6: * This file is part of the Nexus framework.
7: *
8: * (c) John Paul E. Balandan, CPA <paulbalandan@gmail.com>
9: *
10: * For the full copyright and license information, please view
11: * the LICENSE file that was distributed with this source code.
12: */
13:
14: namespace Nexus\PHPStan\Rules\Methods;
15:
16: use PhpParser\Node;
17: use PHPStan\Analyser\Scope;
18: use PHPStan\Node\InClassMethodNode;
19: use PHPStan\Rules\Rule;
20: use PHPStan\Rules\RuleErrorBuilder;
21:
22: /**
23: * @implements Rule<InClassMethodNode>
24: */
25: final class MethodNamingRule implements Rule
26: {
27: public function getNodeType(): string
28: {
29: return InClassMethodNode::class;
30: }
31:
32: public function processNode(Node $node, Scope $scope): array
33: {
34: $method = $node->getOriginalNode();
35: $methodName = $method->name->toString();
36: $methodReflection = $node->getMethodReflection();
37: $methodPrototype = $methodReflection->getPrototype();
38:
39: if (
40: $methodPrototype !== $methodReflection
41: && ! str_starts_with($methodPrototype->getDeclaringClass()->getDisplayName(), 'Nexus\\')
42: ) {
43: return [];
44: }
45:
46: if (str_starts_with($methodName, '__')) {
47: if ($method->isMagic()) {
48: return [];
49: }
50:
51: return [
52: RuleErrorBuilder::message(\sprintf(
53: 'Method %s::%s() should not start with double underscores.',
54: $node->getClassReflection()->getDisplayName(),
55: $methodName,
56: ))
57: ->identifier('nexus.methodDoubleUnderscore')
58: ->build(),
59: ];
60: }
61:
62: if (str_starts_with($methodName, '_')) {
63: return [
64: RuleErrorBuilder::message(\sprintf(
65: 'Method %s::%s() should not start with an underscore.',
66: $node->getClassReflection()->getDisplayName(),
67: $methodName,
68: ))
69: ->identifier('nexus.methodUnderscore')
70: ->build(),
71: ];
72: }
73:
74: if (preg_match('/^[a-z][a-zA-Z0-9]+$/', $methodName) !== 1) {
75: return [
76: RuleErrorBuilder::message(\sprintf(
77: 'Method %s::%s() should be written in camelCase format.',
78: $node->getClassReflection()->getDisplayName(),
79: $methodName,
80: ))
81: ->identifier('nexus.methodCasing')
82: ->build(),
83: ];
84: }
85:
86: $errors = [];
87:
88: foreach (array_values($method->params) as $index => $param) {
89: if (! $param->var instanceof Node\Expr\Variable) {
90: continue; // @codeCoverageIgnore
91: }
92:
93: if (! \is_string($param->var->name)) {
94: continue; // @codeCoverageIgnore
95: }
96:
97: if (preg_match('/^[a-z][a-zA-Z0-9]*$/', $param->var->name) !== 1) {
98: $errors[] = RuleErrorBuilder::message(\sprintf(
99: 'Parameter #%d $%s of %s::%s() should be in camelCase with no underscores.',
100: $index + 1,
101: $param->var->name,
102: $node->getClassReflection()->getDisplayName(),
103: $methodName,
104: ))
105: ->identifier('nexus.methodParamNaming')
106: ->line($param->getStartLine())
107: ->build()
108: ;
109: }
110: }
111:
112: return $errors;
113: }
114: }
115: