PHP RFC: Strict Namespace Resolution
- Version: 0.1
- Date: 2026-07-14
- Author: Paul M. Jones, pmjones@pmjones.io
- Status: Draft
- Implementation: https://github.com/php/php-src/pull/22736
- Discussion thread: https://externals.io/message/131929
- Voting thread: tbd
Introduction
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.
Proposal
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:
- A fully-qualified name (
\strlen(),\PHP_INT_MAX) resolves to the global symbol with no namespace lookup. - An imported name reaches the global symbol through the import:
use function strlen;,use function str_repeat as repeat;, and theuse constequivalents. - The
true,false, andnullkeywords are unaffected by the directive.
The declaration follows the strict_types rules:
- it must be the first statement in the file;
- it cannot use block mode;
- its value must be
0or1;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.
Functions
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)
Constants
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)
Backward Incompatible Changes
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.
Proposed PHP Version(s)
PHP 8.6.
RFC Impact
To the Ecosystem
None; code that does not opt in behaves as before.
To Existing Extensions
None.
To SAPIs
None.
Open Issues
None known.
Future Scope
- The companion Function Autoloading RFC is assisted by but does not strictly require this RFC.
Voting Choices
Primary Vote requiring a 2/3 majority to accept the RFC:
Patches and Tests
Implementation: php/php-src pull request #22736.
Tests:
Zend/tests/strict_namespace_constants.phpt: the fallback is disabled for unqualified constants, whileuse constand fully-qualified names still reach globals;Zend/tests/strict_namespace_bad_value.phpt: the value must be0or1;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.
Implementation
After the RFC is implemented, this section should contain:
- the version(s) it was merged into
- a link to the git commit(s)
- a link to the PHP manual entry for the feature
References
- the companion Function Autoloading RFC;
- rfc/core-autoloading (Gina P. Banyard / Dan Ackroyd, 2023), which discussed namespaced-name resolution and the cost of probing the global table.
Rejected Features
- Strict resolution by default. It would break code that relies on unqualified namespaced calls reaching globals, so the directive is opt-in, defaulting to
0. use function/use constas 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.- Per-
useor per-statement opt-in. Rejected for the file-scopeddeclare, which mirrorsstrict_typesand resolves once at compile time. - Other directive names.
strict_names,namespace_fallback=0, and the like were considered;strict_namespaceparallelsstrict_types.
Changelog
- 2026-07-14: Initial draft (0.1), extracted from the Function Autoloading RFC as a standalone proposal.