Skip to content

Commit 1c995ad

Browse files
committed
feature #306 Checking on reserved keywords for class name validity. (SerkanYildiz)
This PR was squashed before being merged into the 1.0-dev branch (closes #306). Discussion ---------- Checking on reserved keywords for class name validity. Validator should also check if the given class name is a reserved keyword or not. However we have to come up with a better exception message, since this one does not reflect the error. Any suggestion? Thanks for your help @weaverryan during #SymfonyConHackDay2018 Fixes #305 Commits ------- f308470 Move validation logic into Validator. a419b8f Checking on reserved keywords for class name validity.
2 parents 77dad0f + f308470 commit 1c995ad

File tree

3 files changed

+37
-2
lines changed

3 files changed

+37
-2
lines changed

src/Str.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,8 @@
1111

1212
namespace Symfony\Bundle\MakerBundle;
1313

14-
use Symfony\Component\DependencyInjection\Container;
1514
use Doctrine\Common\Inflector\Inflector;
15+
use Symfony\Component\DependencyInjection\Container;
1616

1717
/**
1818
* @author Javier Eguiluz <[email protected]>

src/Validator.php

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,13 +27,35 @@ public static function validateClassName(string $className, string $errorMessage
2727
{
2828
// remove potential opening slash so we don't match on it
2929
$pieces = explode('\\', ltrim($className, '\\'));
30+
$shortClassName = Str::getShortClassName($className);
31+
32+
$reservedKeywords = ['__halt_compiler', 'abstract', 'and', 'array',
33+
'as', 'break', 'callable', 'case', 'catch', 'class',
34+
'clone', 'const', 'continue', 'declare', 'default', 'die', 'do',
35+
'echo', 'else', 'elseif', 'empty', 'enddeclare', 'endfor',
36+
'endforeach', 'endif', 'endswitch', 'endwhile', 'eval',
37+
'exit', 'extends', 'final', 'for', 'foreach', 'function',
38+
'global', 'goto', 'if', 'implements', 'include',
39+
'include_once', 'instanceof', 'insteadof', 'interface', 'isset',
40+
'list', 'namespace', 'new', 'or', 'print', 'private',
41+
'protected', 'public', 'require', 'require_once', 'return',
42+
'static', 'switch', 'throw', 'trait', 'try', 'unset',
43+
'use', 'var', 'while', 'xor',
44+
'int', 'float', 'bool', 'string', 'true', 'false', 'null', 'void',
45+
'iterable', 'object', '__FILE__', '__LINE__', '__DIR__', '__FUNCTION__', '__CLASS__',
46+
'__METHOD__', '__NAMESPACE__', '__TRAIT__',
47+
];
3048

3149
foreach ($pieces as $piece) {
3250
if (!preg_match('/^[a-zA-Z_\x7f-\xff][a-zA-Z0-9_\x7f-\xff]*$/', $piece)) {
3351
$errorMessage = $errorMessage ?: sprintf('"%s" is not valid as a PHP class name (it must start with a letter or underscore, followed by any number of letters, numbers, or underscores)', $className);
3452

3553
throw new RuntimeCommandException($errorMessage);
3654
}
55+
56+
if (\in_array(strtolower($shortClassName), $reservedKeywords, true)) {
57+
throw new RuntimeCommandException(sprintf('"%s" is a reserved keyword and thus cannot be used as class name in PHP.', $shortClassName));
58+
}
3759
}
3860

3961
// return original class name

tests/ValidatorTest.php

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,4 +49,17 @@ public function testInvalidScale()
4949

5050
Validator::validateScale(31);
5151
}
52-
}
52+
53+
public function testValidateClassName()
54+
{
55+
$this->assertSame('\App\Service\Foo', Validator::validateClassName('\App\Service\Foo'));
56+
$this->assertSame('Foo', Validator::validateClassName('Foo'));
57+
}
58+
59+
public function testInvalidClassName()
60+
{
61+
$this->expectException(RuntimeCommandException::class);
62+
$this->expectExceptionMessage('"Class" is a reserved keyword and thus cannot be used as class name in PHP.');
63+
Validator::validateClassName('App\Entity\Class');
64+
}
65+
}

0 commit comments

Comments
 (0)