Name Qualification
The qualification section decides how fully class, function and constant names are written: bare,
imported with a use statement, or fully qualified with a leading backslash. It decides separately for classes from
another namespace and for global classes, functions and constants, and once more separately for the functions and constants the
PHP compiler can optimize.
A name can be written in three ways, and each key of the section takes a value for one of them:
bare: the bare name,strlen(), which inside a namespace reaches the global function only at runtime,imported: the name from ausestatement,use function strlen;and thenstrlen(),backslashed: the name with a leading backslash,\strlen().
If you accept more than one form, write a list: every form in it passes, and a name that matches none of them is rewritten to
the first one. This is exactly what the symfony standard wants: a global class with a backslash; a global function or
constant with a backslash or bare, but never imported; and the same for the functions and constants the compiler can optimize. In
the standard, this takes five lines of this section, and the example adds only imports.unused:
qualification:
class:
global: backslashed
function:
global: [backslashed, bare]
optimized: [backslashed, bare]
constant:
global: [backslashed, bare]
optimized: [backslashed, bare]
imports:
unused: forbidden
namespace App\Report;
use App\Shop\Order;
use DateTimeImmutable; // The import of `DateTimeImmutable` is unused.
use function sprintf; // Global function `sprintf()` must not be imported.
function stamp(Order $order): string
{
$date = new DateTimeImmutable; // Global class `DateTimeImmutable` must be written with the leading backslash.
return sprintf('%s: %d', $date->format('Y-m-d'), \count($order->items)) . PHP_EOL; // Global function `sprintf()` must be written with the leading backslash.
}
namespace App\Report;
use App\Shop\Order;
function stamp(Order $order): string
{
$date = new \DateTimeImmutable;
return \sprintf('%s: %d', $date->format('Y-m-d'), \count($order->items)) . PHP_EOL;
}
\count() with the backslash and the bare PHP_EOL stayed, because the list allows both forms. The
imported sprintf() and DateTimeImmutable got a backslash, and the imports that were no longer needed
disappeared. The import of the class Order from another namespace stayed, because class.otherNamespace
decides on it.
Classes behave differently from global functions and constants. In the namespace App, an unqualified class name
like Exception always means App\Exception, so a global class cannot be written bare, only imported or
qualified. An unqualified function or constant, on the other hand, reaches the global one when the namespace does not declare one
with the same name. The page Functions and Constants in Namespaces explains why
this is uncertain for a tool and how to remove the uncertainty.
qualification:
class:
otherNamespace: imported
global: backslashed
function:
global: bare
optimized: imported
imports:
unused: forbidden
With this configuration, a class from another namespace is imported, a global class gets a backslash, global functions stay
bare, and only those the PHP compiler can optimize are imported. imports.unused removes the imports that are no
longer needed:
namespace App\Model;
use Exception; // The import of `Exception` is unused.
class Cart
{
public function add(array $items, string $name): int
{
if (count($items) > 10 || strlen($name) === 0) { // Global function `count()` must be imported. // Global function `strlen()` must be imported.
throw new Exception('Too many items'); // Global class `Exception` must be written with the leading backslash.
}
$clock = new \App\Util\Clock; // The fully qualified name `\App\Util\Clock` must be imported.
return \array_sum($items); // Global function `array_sum()` must be written without the leading backslash.
}
}
namespace App\Model;
use App\Util\Clock;
use function count;
use function strlen;
class Cart
{
public function add(array $items, string $name): int
{
if (count($items) > 10 || strlen($name) === 0) {
throw new \Exception('Too many items');
}
$clock = new Clock;
return array_sum($items);
}
}
qualification.leadingBackslash removes a backslash that changes nothing: in a file without a namespace, and
anywhere before true, false and null. A backslash at the start of an import is the job of
imports.leadingBackslash.
Compiler Optimizations
The PHP compiler can replace calls to about thirty functions such as strlen(), count() or
is_array() with a single instruction, and it can evaluate constants such as PHP_VERSION_ID in advance.
But it must know at compile time that the name refers to a global function, which means the name is imported or has a backslash.
The keys function.optimized and constant.optimized decide on exactly these names, and
function.global and constant.global do not apply to them. For functions, the arguments also matter: the
compiler optimizes in_array() only with an array written directly in the call. A function belongs to
function.optimized in the whole namespace when the code calls it this way at least once there; otherwise
function.global decides on it, because an import that makes nothing faster is useless. For constants, the place
decides: PHP_VERSION_ID helps the compiler in a condition, not as a function argument. The page Optimizations of Functions and Constants describes what exactly PHP does and how
much it gains.
So each name belongs to exactly one key. Where function.optimized is keep, the optimized functions
stay as they are: function.global: bare by itself removes the backslash from \array_map(), but leaves
\strlen() and \count() untouched. If you want all functions written the same way, write the value for
the whole kind, function: bare, and it applies to every place that accepts it: global,
optimized and currentNamespace. The same holds for constants.
How an optimized call is written has one more consequence: named and unpacked arguments turn the optimization off. Where
function.optimized writes a function as imported or with a backslash, DressCode rewrites the named arguments of its
calls to positional ones and reports an unpacked argument.
Risky Fixes
Switching a bare function to an imported one, or the other way round, is safe only when the namespace declares no function with
the same name. This cannot be seen from a single file, so this is a risky fix: it waits for your permission until the
configuration sets nameResolution: certain.
With it, DressCode knows what is in your namespaces and makes these fixes right away.
qualification.currentClass
How a class refers to itself in an expression: a static access, an instantiation, an instanceof.
self: the class namedselfinside itselfkeep: nothing is enforced, the code stays as it is
Default keep · standards: perCs keep, psr12 keep, nette
self, symfony keep, laravel keep · covers self_accessor,
SlevomatCodingStandard.Classes.UselessLateStaticBinding, Squiz.Classes.SelfMemberReference
qualification.staticInFinalClass
self for static in a class no subclass can extend, a final class, an anonymous class, an enum:
self::create(), new self.
The return type static stays, saying what a subclass would return.
required: always therekeep: nothing is enforced, the code stays as it is
Default keep · standards: perCs keep, psr12 keep, nette
keep, symfony keep, laravel required · covers
self_static_accessor, SlevomatCodingStandard.Classes.UselessLateStaticBinding
qualification.class.otherNamespace
A class, interface, trait or enum of a namespace other than that of the file.
A name relative to an import or to the namespace, Shop\Order, stays as it is.
imported: imported,use Acme\Shop\Order;andOrderbackslashed: with the leading backslash,\Acme\Shop\Order- a list of these words, where each one passes and code matching none of them is written like the first
keep: nothing is enforced, the code stays as it is
Default keep · standards: perCs keep, psr12 keep, nette
imported, symfony keep, laravel imported · covers
fully_qualified_strict_types, SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly
qualification.function.otherNamespace
A function of a namespace other than that of the file.
imported: imported,use function Acme\Text\normalize;andnormalize()backslashed: with the leading backslash,\Acme\Text\normalize()- a list of these words, where each one passes and code matching none of them is written like the first
keep: nothing is enforced, the code stays as it is
Default keep · standards: perCs keep, psr12 keep, nette
keep, symfony keep, laravel keep ·
covers SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly
qualification.constant.otherNamespace
A constant of a namespace other than that of the file.
imported: imported,use const Acme\Shop\STATUS_PAID;andSTATUS_PAIDbackslashed: with the leading backslash,\Acme\Shop\STATUS_PAID- a list of these words, where each one passes and code matching none of them is written like the first
keep: nothing is enforced, the code stays as it is
Default keep · standards: perCs keep, psr12 keep, nette
keep, symfony keep, laravel keep ·
covers SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly
qualification.class.phpdoc
A class, interface, trait or enum a doc comment names in a type, a class constant or the target of a tag.
A name relative to an import or to the namespace, Shop\Order, stays as it is, and so does a bare one no import
reaches, which a doc comment cannot tell from a type of its own such as list.
imported: imported,use Acme\Shop\Order;and@param Order $order, a class of the namespace of the file bare, a global one where the file imports itbackslashed: with the leading backslash,@param \Acme\Shop\Order $order, a name an import reaches- a list of these words, where each one passes and code matching none of them is written like the first
keep: nothing is enforced, the code stays as it is
Default keep · standards: perCs keep, psr12 keep, nette
imported, symfony keep, laravel imported ·
covers fully_qualified_strict_types
qualification.class.currentNamespace
A class, interface, trait or enum of the namespace of the file, Order in namespace Acme\Shop.
bare: bare,Orderrelative to the namespacebackslashed: with the leading backslash,\Acme\Shop\Order- a list of these words, where each one passes and code matching none of them is written like the first
keep: nothing is enforced, the code stays as it is
Default keep · standards: perCs keep, psr12 keep, nette
bare, symfony keep, laravel bare · covers
fully_qualified_strict_types, SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly
qualification.function.currentNamespace
A function of the namespace of the file, normalize() in namespace Acme\Text.
bare: bare,normalize()relative to the namespacebackslashed: with the leading backslash,\Acme\Text\normalize()- a list of these words, where each one passes and code matching none of them is written like the first
keep: nothing is enforced, the code stays as it is
Default keep · standards: perCs keep, psr12 keep, nette
keep, symfony keep, laravel keep ·
covers SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly
qualification.constant.currentNamespace
A constant of the namespace of the file, STATUS_PAID in namespace Acme\Shop.
bare: bare,STATUS_PAIDrelative to the namespacebackslashed: with the leading backslash,\Acme\Shop\STATUS_PAID- a list of these words, where each one passes and code matching none of them is written like the first
keep: nothing is enforced, the code stays as it is
Default keep · standards: perCs keep, psr12 keep, nette
keep, symfony keep, laravel keep ·
covers SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly
qualification.function.optimized
A global function whose call PHP compiles to one opcode once it knows the function is global, count(),
strlen(), is_int() and the others; a call of it written imported or with the backslash has its arguments
passed positionally and an unpacked one reported.
A function is optimized in a namespace where one of its calls there is, an unpacked or named argument aside,
in_array() only with a constant array, and every reference to it in that namespace is then written so; one none of
whose calls is optimized is decided by function.global.
imported: imported,use function strlen;, so that the compiler optimizes itbackslashed: with the leading backslash,\strlen(), so that the compiler optimizes itbare: bare,strlen(), forgoing the optimization- a list of these words, where each one passes and code matching none of them is written like the first
keep: nothing is enforced, the code stays as it is
Default keep · standards: perCs keep, psr12 keep, nette
keep, symfony [backslashed, bare], laravel keep · covers
global_namespace_import, native_function_invocation,
SlevomatCodingStandard.Namespaces.FullyQualifiedGlobalFunctions,
SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly, SlevomatCodingStandard.PHP.OptimizedFunctionsWithoutUnpacking
qualification.class.global
A class of the global namespace referenced in a namespace, DateTime, which a bare name there does not reach.
imported: imported,use DateTime;andDateTimebackslashed: with the leading backslash,\DateTime- a list of these words, where each one passes and code matching none of them is written like the first
keep: nothing is enforced, the code stays as it is
Default keep · standards: perCs keep, psr12 keep, nette
keep, symfony backslashed, laravel keep · covers
global_namespace_import, SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly
qualification.function.global
A global function called in a namespace, ucfirst(), but one PHP optimizes a call of there, which
function.optimized decides.
Not a function of the namespace of the file, nor a name in a file without a namespace, which
qualification.leadingBackslash decides.
bare: bare,ucfirst()without an import or a backslash, reached by the fallback at run timeimported: imported,use function ucfirst;anducfirst()backslashed: with the leading backslash,\ucfirst()- a list of these words, where each one passes and code matching none of them is written like the first
keep: nothing is enforced, the code stays as it is
Default keep · standards: perCs keep, psr12 keep, nette
keep, symfony [backslashed, bare], laravel keep · covers
global_namespace_import, native_function_invocation,
SlevomatCodingStandard.Namespaces.FullyQualifiedGlobalFunctions, SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly
qualification.constant.global
A global constant in a namespace, PHP_EOL, but where the compiler computes with it, which
constant.optimized decides.
bare: bare,PHP_EOLwithout an import or a backslash, reached by the fallback at run timeimported: imported,use const PHP_EOL;andPHP_EOLbackslashed: with the leading backslash,\PHP_EOL- a list of these words, where each one passes and code matching none of them is written like the first
keep: nothing is enforced, the code stays as it is
Default keep · standards: perCs keep, psr12 keep, nette
keep, symfony [backslashed, bare], laravel keep · covers
global_namespace_import, native_constant_invocation,
SlevomatCodingStandard.Namespaces.FullyQualifiedGlobalConstants, SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly
qualification.constant.optimized
A constant of PHP the compiler computes with once it knows the constant is global, PHP_VERSION_ID in a condition,
PHP_INT_MAX in a constant expression.
A constant merely passed to a call is not one the compiler computes with.
imported: imported,use const PHP_VERSION_ID;, so that the compiler computes with itbackslashed: with the leading backslash,\PHP_VERSION_ID, so that the compiler computes with itbare: bare,PHP_VERSION_ID, forgoing the optimization- a list of these words, where each one passes and code matching none of them is written like the first
keep: nothing is enforced, the code stays as it is
Default keep · standards: perCs keep, psr12 keep, nette
keep, symfony [backslashed, bare], laravel keep · covers
global_namespace_import, native_constant_invocation,
SlevomatCodingStandard.Namespaces.FullyQualifiedGlobalConstants, SlevomatCodingStandard.Namespaces.ReferenceUsedNamesOnly
qualification.leadingBackslash
The leading backslash of a name where it changes nothing, in a file without a namespace, \strlen() and
new \DateTime, and before true, false and null anywhere.
forbidden: never therekeep: nothing is enforced, the code stays as it is
Default keep · standards: perCs keep, psr12 keep, nette
forbidden, symfony keep, laravel keep ·
covers PhpCsFixerCustomFixers/no_leading_slash_in_global_namespace