Skip to content

Commit 8eda466

Browse files
authored
Merge pull request #7 from Space48/native-function-invocation-sniff
Add new PhpSc rule: NativeFunctionInvocation.
2 parents bd4a178 + 55ca9b0 commit 8eda466

File tree

3 files changed

+148
-0
lines changed

3 files changed

+148
-0
lines changed
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
<?php declare(strict_types = 1);
2+
3+
namespace Space48\CodeQuality\RuleSets\PhpCs\Space48Extra\Sniffs;
4+
5+
use PHP_CodeSniffer\Files\File as PHP_CodeSniffer_File;
6+
use PHP_CodeSniffer\Sniffs\Sniff as PHP_CodeSniffer_Sniff;
7+
use PHP_CodeSniffer\Standards\Generic\Sniffs\PHP\ForbiddenFunctionsSniff;
8+
9+
class NativeFunctionInvocationSniff extends ForbiddenFunctionsSniff
10+
{
11+
12+
const SET_COMPILER_OPTIMIZED = 'compiler_optimized';
13+
const SET_INTERNAL = 'internal';
14+
15+
public $set = self::SET_INTERNAL;
16+
17+
/**
18+
* @return array
19+
*/
20+
public function register()
21+
{
22+
if ($this->set === self::SET_INTERNAL) {
23+
$this->forbiddenFunctions = $this->formatForForbidden($this->getAllInternalFunctionsNormalized());
24+
} else {
25+
$this->forbiddenFunctions = $this->formatForForbidden($this->getAllCompilerOptimizedFunctionsNormalized());
26+
}
27+
28+
return parent::register();
29+
}
30+
31+
/**
32+
* @param array $functionNames
33+
* @return array
34+
*/
35+
private function formatForForbidden(array $functionNames): array
36+
{
37+
$forbiddenFunctions = [];
38+
foreach (array_keys($functionNames) as $name) {
39+
$forbiddenFunctions[$name] = $name;
40+
}
41+
42+
return $forbiddenFunctions;
43+
}
44+
45+
/**
46+
* @param \PHP_CodeSniffer\Files\File $phpcsFile
47+
* @param int $stackPtr
48+
* @param string $functionName
49+
* @param null|string $pattern
50+
*/
51+
protected function addError($phpcsFile, $stackPtr, $functionName, $pattern = null)
52+
{
53+
$phpcsFile->addError($this->getErrorMessage(), $stackPtr, 'Encountered', [$functionName, $functionName]);
54+
}
55+
56+
/**
57+
* @return string
58+
*/
59+
private function getErrorMessage(): string
60+
{
61+
return 'Native function "%s" must be invoked with root namespace: "\%s"';
62+
}
63+
64+
/**
65+
* @return array<string, true> normalized function names of which the PHP compiler optimizes
66+
*/
67+
private function getAllCompilerOptimizedFunctionsNormalized(): array
68+
{
69+
return $this->normalizeFunctionNames([
70+
// @see https://github.com/php/php-src/blob/PHP-7.4/Zend/zend_compile.c "zend_try_compile_special_func"
71+
'array_key_exists',
72+
'array_slice',
73+
'assert',
74+
'boolval',
75+
'call_user_func',
76+
'call_user_func_array',
77+
'chr',
78+
'count',
79+
'defined',
80+
'doubleval',
81+
'floatval',
82+
'func_get_args',
83+
'func_num_args',
84+
'get_called_class',
85+
'get_class',
86+
'gettype',
87+
'in_array',
88+
'intval',
89+
'is_array',
90+
'is_bool',
91+
'is_double',
92+
'is_float',
93+
'is_int',
94+
'is_integer',
95+
'is_long',
96+
'is_null',
97+
'is_object',
98+
'is_real',
99+
'is_resource',
100+
'is_string',
101+
'ord',
102+
'strlen',
103+
'strval',
104+
// @see https://github.com/php/php-src/blob/php-7.2.6/ext/opcache/Optimizer/pass1_5.c
105+
'constant',
106+
'define',
107+
'dirname',
108+
'extension_loaded',
109+
'function_exists',
110+
'is_callable',
111+
]);
112+
}
113+
114+
/**
115+
* @return array<string, true> normalized function names of all internal defined functions
116+
*/
117+
private function getAllInternalFunctionsNormalized(): array
118+
{
119+
return $this->normalizeFunctionNames(get_defined_functions()['internal']);
120+
}
121+
122+
/**
123+
* @param string[] $functionNames
124+
*
125+
* @return array<string, true> all function names lower cased
126+
*/
127+
private function normalizeFunctionNames(array $functionNames): array
128+
{
129+
foreach ($functionNames as $index => $functionName) {
130+
$functionNames[strtolower($functionName)] = true;
131+
unset($functionNames[$index]);
132+
}
133+
134+
return $functionNames;
135+
}
136+
}
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
<?xml version="1.0"?>
2+
<ruleset name="Space48Extra">
3+
<description>Space48 Extra</description>
4+
<rule ref="vendor/space48/magento2-code-quality/rulesets/PhpCs/Space48Extra/Sniffs/NativeFunctionInvocationSniff.php">
5+
<properties>
6+
<property name="set" value="compiler_optimized" />
7+
</properties>
8+
</rule>
9+
</ruleset>

rulesets/ruleset.xml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,9 @@
33
<ruleset name="Space48 Coding Standard">
44
<arg name="extensions" value="php,phtml" />
55

6+
<rule ref="vendor/space48/magento2-code-quality/rulesets/PhpCs/Space48Extra/extra.xml">
7+
</rule>
8+
69
<rule ref="vendor/magento/magento-coding-standard/Magento2/ruleset.xml">
710
<!-- Serves no purpose -->
811
<exclude name="Squiz.Commenting.ClassComment.Missing" />

0 commit comments

Comments
 (0)