rfc:group_use_declarations

PHP RFC: Group Use Declarations

Introduction

This RFC aims to improve current PHP namespace implementation by introducing the concept of Group Use Declarations:

// Proposed group use syntax:
 
use FooLibrary\Bar\Baz\{ ClassA, ClassB, ClassC, ClassD as Fizbo };
 
// Compared to current use syntax:
 
use FooLibrary\Bar\Baz\ClassA;
use FooLibrary\Bar\Baz\ClassB;
use FooLibrary\Bar\Baz\ClassC;
use FooLibrary\Bar\Baz\ClassD as Fizbo;

Proposal

Group use declarations are used to cut verbosity when importing multiple entities from a common namespace. Using common PHP library examples, the following use declarations are equivalents:

// Current use syntax:
 
use Doctrine\Common\Collections\Expr\Comparison;
use Doctrine\Common\Collections\Expr\Value;
use Doctrine\Common\Collections\Expr\CompositeExpression;
 
// Proposed group use syntax:
 
use Doctrine\Common\Collections\Expr\{ Comparison, Value, CompositeExpression };

Compound Namespaces

Compound namespaces are also allowed. For instance, the following use declarations are equivalents:

// Current use syntax:
 
use Symfony\Component\Console\Helper\Table;
use Symfony\Component\Console\Input\ArrayInput;
use Symfony\Component\Console\Output\NullOutput;
use Symfony\Component\Console\Question\Question;
use Symfony\Component\Console\Input\InputInterface;
use Symfony\Component\Console\Output\OutputInterface;
use Symfony\Component\Console\Question\ChoiceQuestion as Choice;
use Symfony\Component\Console\Question\ConfirmationQuestion;
 
// Proposed group use syntax:
 
use Symfony\Component\Console\{
  Helper\Table,
  Input\ArrayInput,
  Input\InputInterface,
  Output\NullOutput,
  Output\OutputInterface,
  Question\Question,
  Question\ChoiceQuestion as Choice,
  Question\ConfirmationQuestion,
};

This is also a real use case. Check out the Laravel source code:

Non Mixed Use Declarations

As expected, non mixed group use declarations are also supported:

// Current use syntax:
 
use function foo\math\sin, foo\math\cos, foo\math\cosh;
use const foo\math\PI, foo\math\E, foo\math\GAMMA, foo\math\GOLDEN_RATIO;
 
// Proposed non mixed group use syntax:
 
use function foo\math\{ sin, cos, cosh };
use const foo\math\{ PI, E, GAMMA, GOLDEN_RATIO };

Mixed Use Declarations

The current implementation of namespaces does not allow mixed imports of functions, constants and classes. The proposed implementation would allow mixed imports like this:

// Current use syntax:
 
use foo\math\Math;
use const foo\math\PI;
use function foo\math\sin, foo\math\cos, foo\math\cosh;
 
// Proposed mixed group use syntax:
 
use foo\math\{ Math, const PI, function sin, function cos, function cosh };

Justification

Group use declaratations facilitates to import multiple structures from a common namespace and cuts a good level of verbosity in most cases. Group use declaratations makes it easier to identify that multiple imported entities belong to the same module.

For the first example in this RFC, instead of having to read 'FooLibrary\Bar\Baz\Biz' four times to see that the namespace is the same for each entry, it is clear by the grouping syntax that the entries all come from the same namespace.

The same advantage regardless readability is noticeable on patch diffs that a dependency on a new module has been introduced. For instance, a patch that adds a new dependency on “Consolidation” namespace has been introduced:

use Symfony\Component\Console\Question\ConfirmationQuestion;
use Symfony\Component\Console\Question\ChoiceQuestion as Choice;
+use Symfony\Component\Console\Question\OptionQuestion;
+use Symfony\Component\Consolidation\Question\OptionQuestion;
use Symfony\Component\Console\Question\Question;

With the current use syntax it's necessary to read to the 30th character of the 2nd modified line to realize that the patch adds a new dependency. The proposed syntax is much more readable:

use Symfony\Component\Console\Question\{
    ConfirmationQuestion,
    ChoiceQuestion as Choice,
+   OptionQuestion,
    Question,
};
+use Symfony\Component\Consolidation\Question\OptionQuestion;

Opinions

This is a condensed list of unique reactions collected during email discussions and research phase:

In Favor Or Partially Favorable

  • It's more readable and makes it easier to import classes, constants and functions in a concise way.
  • It seems like a step in the right direction to improving namespaces and more closely approximating the better systems (like Python module imports).
  • We really should have a shorthand for condensing use declarations. I wonder if the syntax could feel more “PHP” but maybe I'm just nitpicking.
  • The benefits for users which are using IDEs seems marginal, but all other users could actually benefit from it so I'm in favor of the proposal.
  • I would like to have it with the option for non enforced trailing “\” (T_NS_SEPARATOR) syntax.
  • I'm in favor of the shorthand syntax but I don't care about the nesting option.

=> Requests for a syntax variation without a trailing “\” were quite frequent and resulted in a voting option.
=> Based on overall feedback the nested namespace option was removed.

Contrary Or Indifferent

  • With proper tooling I almost can't remember when I wrote use statements “by hand” so I don't need it.
  • The search for literal full qualified namespaces can become less straightforward.

About The Syntax Choice

The syntax chosen is inline with the current trait adaptation syntax to make it look and feel similar to existing PHP standards. Such design choice allows the feature to stay familiar and intuitive to most PHP user base.

Options

Trailing T_NS_SEPARATOR

During research phase a syntax variant without a trailing “\” (T_NS_SEPARATOR) emerged as a debatable option:

// with trailing "\"
 
use Foo\Bar\Baz\{ ClassA, ClassB, ClassC, ClassD };
 
// vs
// without trailing "\"
 
use Foo\Bar\Baz{ ClassA, ClassB, ClassC, ClassD };

This shall be addressed on voting phase: should a trailing “\” be enforced or removed from syntax?

Proposed PHP Version(s)

This is proposed for the next PHP x, which at the time of this writing would be PHP 7.

RFC Impact

On Functional Programming / Autoloading

Group use declarations is also very helpful for the PHP user base more fond to the functional programming paradigms. This RFC would be especially important if PHP finally gets function autoloading.

Currently, sets of independent functions have to be implemented as static classes. But with function autoloading, they’d have to be imported independently, and that would lead to way too many use statements without this feature. Here is an example to illustrate this impact using the well known Nikita's iter functional library:

// Current use syntax:
 
use function iter\range;
use function iter\map;
use function iter\filter;
use function iter\apply;
use function iter\reduce;
use function iter\fn\operator;
 
// Proposed syntax:
 
use function iter\{ range, map, filter, apply, reduce, fn\operator };

On Backward Compatibility

This RFC is backwards compatible with previous PHP releases. It's worth to add that the patch will not affect runtime performance.

Unaffected PHP Functionality

Original namespace implementation is not affected by the addition of group use declarations. Current syntax would still be valid.

Support in other languages

Other languages have similar ways to import multiple entities from a given package or module:

  • Rust Language has a very similar syntax use a::b::{c, d, e, f};
  • Scala has a very similar syntax use a.b.{c, d, e, f};
  • Python has a different syntax but with the same objective: from fibo import fib, fib2, fib3

Votes

As this is a language change, this RFC requires a 2/3 majority of Yes votes (with or without trailing “\”) to pass. Voting started on 2015-02-11 and will end on 2015-02-25.

Should Grouped Use Declarations be added to PHP 7
Real name Yes - with a trailing "\" Yes - without a trailing "\" No
ab (ab)   
aharvey (aharvey)   
ajf (ajf)   
alan_k (alan_k)   
bishop (bishop)   
brandon (brandon)   
danack (danack)   
daverandom (daverandom)   
davey (davey)   
derick (derick)   
diegopires (diegopires)   
dm (dm)   
dragoonis (dragoonis)   
fmargaine (fmargaine)   
francois (francois)   
fredemmott (fredemmott)   
galvao (galvao)   
guilhermeblanco (guilhermeblanco)   
hywan (hywan)   
indeyets (indeyets)   
ircmaxell (ircmaxell)   
irker (irker)   
jedibc (jedibc)   
jgmdev (jgmdev)   
kalle (kalle)   
kinncj (kinncj)   
klaussilveira (klaussilveira)   
krakjoe (krakjoe)   
laruence (laruence)   
lcobucci (lcobucci)   
leigh (leigh)   
levim (levim)   
lstrojny (lstrojny)   
malukenho (malukenho)   
marco (marco)   
mbeccati (mbeccati)   
mfischer (mfischer)   
mike (mike)   
nikic (nikic)   
olemarkus (olemarkus)   
pajoye (pajoye)   
pauloelr (pauloelr)   
peehaa (peehaa)   
philstu (philstu)   
pollita (pollita)   
rdlowrey (rdlowrey)   
rdohms (rdohms)   
reeze (reeze)   
royopa (royopa)   
salathe (salathe)   
santiagolizardo (santiagolizardo)   
seld (seld)   
stas (stas)   
subjective (subjective)   
treffynnon (treffynnon)   
tyrael (tyrael)   
yohgaki (yohgaki)   
zeev (zeev)   
Final result: 32 7 19
This poll has been closed.

Discussion in a Nutshell

In case you missed the discussion. This section lists the common counter points towards this RFC and how they were replied by the RFC author and supporters on mailing lists and media:

My IDE already does the imports for me and folds the namespaces so I don't need this feature

We should create usable languages by design rather than languages only usable by tooling. Tooling can be very important but the moment you notice a stack of tools is needed to have a reasonable experience and readability with a programming language then something needs to be improved.

A programming language should be able stand on its own and not require IDE assistance for reasonable use. That's what this RFC does, it brings a very common feature already available in many languages employing some kind of namespacing.

The RFC encourages violation of the the SRP and other best practices

This is not true. Nikita already wrote a great response to this on the official PHP mailing list. Beware of the slay of good argumentation ahead: http://news.php.net/php.internals/82622

We should have "first class packages" first, therefore we can't approve this RFC now!

This is painfully illogic. Group use declarations and “first class packages” are completely orthogonal features. Having group use declarations will only help to support long awaited features like “first class namespaces” or “function autoloading”. The order in which the features are proposed or accepted is irrelevant in this case. We can have the feature now.

Doing so prior to a major PHP7 release is, in fact, the best hour to approve this RFC.

We should go for Python's syntax instead and reject this RFC

I doubt Python syntax will ever be proposed for PHP because it would require the the from keyword to be reserved, hence one of the reasons it was discarded during research and discussion. Other reason is that the glob brace syntax is more tailored for PHP and it is a good choice.

Patches and Tests

The implementation aims to be minimal and of easy maintenance. I created a PR so that the patch diff can be viewed easily: https://github.com/php/php-src/pull/1005

The current implementation can be found on my PHP fork. You can also directly contribute to this RFC by sending a pull request to https://github.com/marcioAlmada/RFCs.

References

There is no found record related to group use declarations on mailing lists.

Changelog

  • 0.1 - first proposal
  • 0.2 - added trailing “\” syntax to proposal
  • 0.3 - added voting option for a non trailing “\” syntax
  • 0.4 - RFC was simplified: “nesting” voting option was removed

Acknowledgements

Thanks to:

  1. Daniel Ackroyd for reviewing this RFC.
  2. Andrea and Rangad for their insightful opinions.
  3. NikiC for providing accurate information about the PHP implementation.
rfc/group_use_declarations.txt · Last modified: 2017/09/22 13:28 by 127.0.0.1