====== PHP RFC: user-from syntax for namespace use declarations ======
* Version: 0.1
* Date: 2026-01-05
* Author: Stuardo Rodríguez, str@maphpia.com
* Status: Under Discussion
* Implementation: https://github.com/php/php-src/pull/20844
This RFC proposes an alternative spelling for namespace imports that reads “import X from Y”, as syntax sugar for existing `use` declarations.
===== Introduction =====
This RFC adds an alternative `use` syntax that places the imported symbol(s) first, followed by a shared namespace prefix introduced by `from`.
It is intended to improve readability for imports and to provide a brace-first grouped form for multiple imports from the same namespace.
==== Motivation and Rationale ====
The `use ... from ` makes it easier to scan and (optionally) sort import lists by imported symbol (class/function/const) rather than by namespace prefix. Placing the symbol immediately after `use` makes symbol-first ordering straightforward for humans and formatters, while projects that prefer namespace-first ordering can continue to do so.
Example (symbol-first ordering):
use Carbon from Illuminate\Support;
use Inertia from Inertia;
use SettingService from App\Services;
use Status from App\Models;
use Task from App\Models;
use TaskCreated from App\Events;
use TaskRepository from App\Repositories;
use TaskService from App\Services;
use TaskUpdated from App\Events;
use TaskUpdateData from App\DTOs;
use User from App\Models;
use ZipArchive;
This RFC is pure syntax sugar (no runtime behavior change). The design is intentionally localized: the only notable compatibility surface is the introduction of a contextual/soft keyword token for `from` in `use` declarations.
Adding new syntax to PHP requires a clear and strong justification. The `use ... from` form meets that bar by reducing cognitive friction for developers who regularly move between languages that already use a similar form (e.g., JavaScript's `import X from 'Y'` and Python's `from Y import X`). Making PHP imports resemble these familiar patterns helps onboarding and code review across mixed-language teams and makes the import semantics immediately recognizable to a wider audience.
The combination of improved cross-language familiarity, better symbol-first sorting ergonomics, and low implementation risk provides a compelling rationale for adoption.
===== Proposal =====
==== New syntax ====
The proposal introduces the following additional forms:
1) Single imports (class-like imports):
use Name from Prefix;
use Name from Prefix as Alias;
use Name as Alias from Prefix;
use Service from App\Domain;
2) Group imports (brace-first):
use {A, B as C} from Some\Namespace;
3) Function and const group imports:
use function {fn_a, fn_b} from Some\Namespace;
use const {ConstA, ConstB} from Some\Namespace;
4) Mixed group imports (existing mixed-group behavior, with brace-first `from` form):
use {Php\WebSite, function JS\printTotal, const JS\BUAIKUM} from Mizo\Web;
==== Semantics ====
All new forms are syntax sugar for existing import forms and do not change runtime behavior.
* `use Name from Prefix;` is equivalent to `use Prefix\Name;`
* `use Name from Prefix as Alias;` is equivalent to `use Prefix\Name as Alias;`
* `use Name as Alias from Prefix;` is equivalent to `use Prefix\Name as Alias;`
* `use {A, B as C} from Prefix;` is equivalent to `use Prefix\{A, B as C};`
* `use function {fn_a} from Prefix;` is equivalent to `use function Prefix\{fn_a};`
* `use const {ConstA} from Prefix;` is equivalent to `use const Prefix\{ConstA};`
=== Mixed-group semantics and parsing ===
Mixed groups are syntax sugar for the existing prefix-group form: each entry in the brace list is interpreted as a *suffix* that is appended to the `Prefix`. For example, in
use {Php\WebSite, function JS\printTotal} from Mizo\Web;
both entries are suffixed onto `Mizo\Web` and the statement is equivalent to:
use Mizo\Web\{Php\WebSite, function JS\printTotal};
Entries inside the braces may themselves include namespace separators and will still be treated as suffixes (so `Php\WebSite` becomes `Mizo\Web\Php\WebSite`). A leading backslash on an entry makes it absolute and it will NOT be prefixed. Qualifiers such as `function` and `const` apply to the following name exactly as they do for existing grouped `use` declarations, and `as` aliases are supported per-entry.
==== Compatibility and implementation notes ====
This proposal introduces a new token `T_FROM` (token text: `from`) for use by the parser in `use`-declaration contexts.
To preserve compatibility with existing code that uses `from` as an identifier, `from` is treated as a *contextual* (soft) keyword. Tokenizers/lexers SHOULD emit `T_FROM` only when `from` occurs inside a `use` declaration, and emit `T_STRING` otherwise (method calls, property access, function names/calls, named arguments, etc.).
Implementation note: the Zend scanner must be context-aware (e.g., via lexical state or a scanner flag set after `use` and cleared at the terminating `;` / end-of-tag implicit `;`).
Tooling note:
* AST-based tools are unaffected: `$db->from()` and related identifiers remain valid and produce the same AST.
* Token-stream tools must handle `T_FROM` in `use` contexts.
==== Examples ====
Single imports (comma-separated supported):
use Classname from My\Full as Another, NSname from My\Full;
Brace-first group imports:
use {ClassA, ClassB, ClassC as C} from Some\Namespace;
Function/const group imports:
use function {fn_a, fn_b} from Some\Namespace;
use const {ConstA, ConstB} from Some\Namespace;
Mixed group imports:
use {Php\WebSite, function JS\printTotal, const JS\BUAIKUM} from Mizo\Web;
===== Backward Incompatible Changes =====
* Tokenization change: the string `from` becomes a contextual token and **may** be emitted as `T_FROM` in `use` declarations instead of `T_STRING` in `token_get_all()` / `PhpToken::tokenize()` output.
* Token-stream tools (formatters, linters, IDEs, analyzers) must be updated to handle `T_FROM`.
* Mitigation guidance: token-only tooling should treat `T_FROM` as a keyword only in `use`-declaration contexts; where possible, prefer AST-based parsing.
* This proposal explicitly preserves `function from() {}`, `from()`, method/property names (e.g., `$db->from()`), and named arguments (`fn(from: ...)`).
Impact analysis (e.g. scanning Composer packages) is TBD; we recommend performing a repository-scale scan for uses of `from` as an identifier in third-party libraries and coordinating with major static-analysis and IDE projects to review possible impacts.
===== Proposed PHP Version(s) =====
next PHP 8.x
===== RFC Impact =====
==== To the Ecosystem ====
* Token-based tools will need to recognize `T_FROM`.
* Parsers that implement PHP grammar (or partial grammars) will need to account for the new `use … from …` and brace-first group forms.
==== To Existing Extensions ====
* `ext/tokenizer` exposes a new token constant `T_FROM`.
* No other extension impact is expected.
==== To SAPIs ====
No expected impact.
===== Open Issues =====
* Confirm the intended scope of “soft keyword” behavior for `from` across identifier positions (method names, class names, namespaces, named arguments, etc.).
* Quantify backward compatibility impact by scanning existing codebases for `from` used as an identifier in affected contexts.
* Decide whether mixed-group `from` imports should remain allowed (current implementation supports it).
* Decide whether to allow **static-method imports** (e.g., `use method from Class` as sugar for importing a static method or binding); this has non-trivial grammar and semantic implications (double-colon `::` interactions) and is **out of scope** for the initial proposal — record as a future investigation point.
* Design lexer state transitions for contextual `T_FROM` in the Zend scanner (`Zend/zend_language_scanner.l`) and ensure tests cover multiline, comments, and error recovery.
* Contact maintainers of major token-based tools, IDEs, and static analyzers to coordinate tokenization changes and provide migration guidance and tests.
===== Future Scope =====
* Consider whether to allow additional symmetric forms (e.g. alternative grouping spellings) only if there is strong demand.
* Consider IDE / tooling guidance (formatting conventions) after the syntax is accepted. In particular, provide guidance and formatter options so projects can choose symbol-first or namespace-first sorting (and ideally a configurable formatting rule), and provide recommended defaults and migration guidance for large codebases.
* Consider guidance for how formatters and linters should behave if a future static-method import form is introduced (e.g., `use method from Class`): provide warnings, opt-in formatting rules, and migration helpers to avoid surprising changes across large codebases.
===== Voting Choices =====
Primary Vote requiring a 2/3 majority to accept the RFC:
* Yes
* No
* Abstain
===== Patches and Tests =====
Implementation: https://github.com/php/php-src/pull/20844
Tests (proof of concept):
* Syntax and semantics:
* [[https://github.com/str/php-src/tree/feature/use-from/Zend/tests/use_from_syntax.phpt|Zend/tests/use_from_syntax.phpt]] — basic single-import `use Name from Prefix` forms and simple comma-separated imports
* [[https://github.com/str/php-src/tree/feature/use-from/Zend/tests/use_from_syntax_qualified.phpt|Zend/tests/use_from_syntax_qualified.phpt]] — handling of qualified and fully-qualified prefixes (leading backslash)
* [[https://github.com/str/php-src/tree/feature/use-from/Zend/tests/use_from_syntax_comprehensive.phpt|Zend/tests/use_from_syntax_comprehensive.phpt]] — comprehensive coverage of combinations and edge cases
* [[https://github.com/str/php-src/tree/feature/use-from/Zend/tests/use_from_syntax_aliases.phpt|Zend/tests/use_from_syntax_aliases.phpt]] — aliasing (`as`) semantics for single and grouped imports
* [[https://github.com/str/php-src/tree/feature/use-from/Zend/tests/use_from_group.phpt|Zend/tests/use_from_group.phpt]] — brace-first group imports for classes, functions and consts
* [[https://github.com/str/php-src/tree/feature/use-from/Zend/tests/use_from_manual_examples.phpt|Zend/tests/use_from_manual_examples.phpt]] — manual-style examples from the RFC demonstrating common usage
* [[https://github.com/str/php-src/tree/feature/use-from/Zend/tests/use_from_as_function_name.phpt|Zend/tests/use_from_as_function_name.phpt]] — ensures `from` remains usable as a function name and call target
* [[https://github.com/str/php-src/tree/feature/use-from/Zend/tests/use_from_as_method_name.phpt|Zend/tests/use_from_as_method_name.phpt]] — ensures instance method named `from` still works (`$db->from()`)
* [[https://github.com/str/php-src/tree/feature/use-from/Zend/tests/use_from_static_method.phpt|Zend/tests/use_from_static_method.phpt]] — ensures static method named `from` still works (`C::from()`)
* [[https://github.com/str/php-src/tree/feature/use-from/Zend/tests/use_from_named_argument.phpt|Zend/tests/use_from_named_argument.phpt]] — ensures `from` can still be used as a named argument label (`fn(from: ...)`)
* [[https://github.com/str/php-src/tree/feature/use-from/Zend/tests/use_from_mixed_group_equivalence.phpt|Zend/tests/use_from_mixed_group_equivalence.phpt]] — demonstrates that `use {A, function B} from P;` is equivalent to `use P\{A, function B};`
* Tokenizer test:
* [[https://github.com/str/php-src/tree/feature/use-from/ext/tokenizer/tests/t_from_token.phpt|ext/tokenizer/tests/t_from_token.phpt]] — tokenizer test asserting that `from` is emitted as `T_FROM` in `use` contexts
* [[https://github.com/str/php-src/tree/feature/use-from/ext/tokenizer/tests/t_from_method_call.phpt|ext/tokenizer/tests/t_from_method_call.phpt]] — tokenizer test asserting `from` is `T_STRING` in `$db->from()` contexts
* [[https://github.com/str/php-src/tree/feature/use-from/ext/tokenizer/tests/t_from_token_get_all.phpt|ext/tokenizer/tests/t_from_token_get_all.phpt]] — token_get_all test verifying `T_FROM` vs `T_STRING` differences
===== 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 =====
Links to external references, discussions, or RFCs.
===== Rejected Features =====
Keep this updated with features that were discussed on the mail lists.
===== Changelog =====
If there are major changes to the initial proposal, please include a short summary with a date or a link to the mailing list announcement here, as not everyone has access to the wikis' version history.