Inside a namespace, PHP resolves an unqualified function or constant name in the current namespace first, then falls back to the global namespace. Unqualified class names do not fall back; they resolve in the current namespace only. For example, an unqualified strlen() in namespace Foo binds to the global strlen(), not Foo\strlen().
This RFC proposes declare(strict_namespace=1), a file-scoped compile-time directive that turns off the global fallback for unqualified function and constant names. When strict_namespace is enabled, unqualified names resolve to the current namespace only, just as class names already do.
declare(strict_namespace=1); namespace Foo; function strlen(string $s): int { return -1; } // Foo\strlen echo strlen('bar'); // -1 (unqualified: Foo\strlen, no fallback) echo \strlen('bar'); // 3 (fully qualified: global strlen)
This proposal is extracted from the Function Autoloading RFC; it serves both as an aid to that RFC and as an independent improvement. Whether or not function autoloading is adopted, this RFC helps make function and constant resolution match class resolution.
declare(strict_namespace=1) disables the global-namespace fallback for the file that declares it. An unqualified function or constant name then resolves only within the current namespace: an unqualified strlen() in namespace Foo is Foo\strlen. If Foo\strlen is not defined, the call will not fall back to the global strlen().
A name still reaches the global table when asked for directly:
\strlen(), \PHP_INT_MAX) resolves to the global symbol with no namespace lookup.use function strlen;, use function str_repeat as repeat;, and the use const equivalents.true, false, and null keywords are unaffected by the directive.
The declaration follows the strict_types rules:
0 or 1; 0 (current behavior) is the default.It resolves entirely at compile time, in the declaring file only. Callers and callees in other files are unaffected, and there is no runtime or JIT cost.
The effect on functions is as follows:
declare(strict_namespace=1); namespace Foo; use function str_repeat as repeat; function strlen(string $s): int { return -1; } // Foo\strlen var_dump(strlen('hello')); // int(-1) (unqualified: Foo\strlen) var_dump(\strlen('hello')); // int(5) (fully qualified: global) var_dump(repeat('ab', 3)); // string(6) "ababab" (imported: global)
The effect on constants is the same. Under strict_namespace=1 an unqualified GREETING in namespace Foo is Foo\GREETING, and a built-in like PHP_INT_MAX resolves to Foo\PHP_INT_MAX unless written \PHP_INT_MAX or imported with use const. Constant expressions follow suit, such as a const value, a parameter default, or an attribute argument. (The true/false/null keywords are unaffected.)
declare(strict_namespace=1); namespace Foo; const PHP_INT_MAX = 42; // Foo\PHP_INT_MAX echo PHP_INT_MAX; // 42 (unqualified: Foo\PHP_INT_MAX) echo \PHP_INT_MAX; // (fully qualified: global constant)
None. The directive is opt-in and defaults to 0, the current behavior. Only a file that declares strict_namespace=1 changes; nothing else is affected.
PHP 8.6.
None; code that does not opt in behaves as before.
None.
None.
None known.
Primary Vote requiring a 2/3 majority to accept the RFC:
Implementation: php/php-src pull request #22736.
Tests:
Zend/tests/strict_namespace_constants.phpt: the fallback is disabled for unqualified constants, while use const and fully-qualified names still reach globals;Zend/tests/strict_namespace_bad_value.phpt: the value must be 0 or 1;Zend/tests/strict_namespace_block_mode.phpt: the declaration cannot use block mode;Zend/tests/strict_namespace_not_first.phpt: the declaration must be the first statement.After the RFC is implemented, this section should contain:
0.use function/use const as the only fix. Importing each name from its own namespace works, but it is a per-name chore in every file; the directive covers the whole file at once.use or per-statement opt-in. Rejected for the file-scoped declare, which mirrors strict_types and resolves once at compile time.strict_names, namespace_fallback=0, and the like were considered; strict_namespace parallels strict_types.