====== 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.