Hi internals!
Some time ago I introduced the following proposal for namespace-scoped
declares:
https://wiki.php.net/rfc/namespace_scoped_declares
The idea is to allow specifying declare directives for a whole library or
project using:
namespace_declare('Vendor\Lib', ['strict_types' => 1]);
I've finally gotten around to implementing this proposal (
https://github.com/php/php-src/pull/2972) and would like to move forward
with it.
The reason why I'm picking it up again is some feedback I received for the
explicit call-time send-by-ref proposal. The main objection seems to be
that the feature has limited usefulness if it's optional rather than
required, because you still can't be sure that something is a by-value
pass, just because no & is present. At the same time, we can't make this
required anytime soon due to the large BC impact.
Namespace-scoped declares are perfectly suited to resolve this problem. We
can introduce a require_explicit_send_by_ref declare directive to make the
call-site annotation required, and libraries/projects can easily opt-in to
it using namespace_declare(). There would be no BC impact, while at the
same time projects could benefit from the additional clarity and
performance improvements immediately.
Thanks,
Nikita
Some time ago I introduced the following proposal for namespace-scoped
declares:https://wiki.php.net/rfc/namespace_scoped_declares
The idea is to allow specifying declare directives for a whole library or
project using:namespace_declare('Vendor\Lib', ['strict_types' => 1]);
I've finally gotten around to implementing this proposal (
https://github.com/php/php-src/pull/2972) and would like to move forward
with it.
Being lazy here because I'm literally on my way out the door and don't
have a moment to parse through the implementation, but can you clarify
how this impact compile-time declares?
<?php
require('a.php");
require('b.php"); // This file has a namespace declaration
require('c.php");
In this example, does a.php wind up getting compiled with a different
set of declares than b.php and c.php?
-Sara
On Mon, Dec 11, 2017 at 8:43 AM, Nikita Popov nikita.ppv@gmail.com
wrote:Some time ago I introduced the following proposal for namespace-scoped
declares:https://wiki.php.net/rfc/namespace_scoped_declares
The idea is to allow specifying declare directives for a whole library or
project using:namespace_declare('Vendor\Lib', ['strict_types' => 1]);
I've finally gotten around to implementing this proposal (
https://github.com/php/php-src/pull/2972) and would like to move forward
with it.Being lazy here because I'm literally on my way out the door and don't
have a moment to parse through the implementation, but can you clarify
how this impact compile-time declares?<?php
require('a.php");
require('b.php"); // This file has a namespace declaration
require('c.php");In this example, does a.php wind up getting compiled with a different
set of declares than b.php and c.php?-Sara
Nope. The namespace_declare() call in this case will throw an Error,
because code using that namespace has already been loaded. The
implementation is careful to ensure that it's never possible to end up in a
situation where the used declare directives are inconsistent.
Nikita
Namespace-scoped declares are perfectly suited to resolve this problem. We
can introduce a require_explicit_send_by_ref declare directive to make the
call-site annotation required, and libraries/projects can easily opt-in to
it using namespace_declare().
Seems solid to me, I would definitely make use of this feature, as I
found adding the declare to each file felt untidy and even a little clumsy.
I certainly like the direction that PHP seems to be moving in terms of
making the script structure more like a compiled application, rather
than a set of independent scripts.
If this doesn't pass, long term I think the main alternative would be to
have a single statement that was like a quasi-include of declarations in
another file, almost like a ".h"
declare_import('/my/namespace/nsprefs.php');
--
Mark Randall
Hi!
The idea is to allow specifying declare directives for a whole library or
project using:namespace_declare('Vendor\Lib', ['strict_types' => 1]);
I am not sure I like this. Namespace is a prefix to a class name.
Anybody can declare a class with any name, and the side-effect that they
would inherit some context, which is completely invisible and would
magically exist somewhere globally, does not seem like a good idea to
me. Moreover, what if something - like older version of the same library
or test or something like that - would have different idea about what
that global state should be? How nice would it be if a piece of
unrelated code could completely change how my code is interpreted? How
nice would it be if whether it works or not would depend on in which
order classes were loaded in this particular request?
Hidden global context has the same smell as php.ini settings, and for
the same reason - but this, as far as I can see, will also be hidden and
depending on file loading order, class loading order, etc. which in big
applications can lead to a lot of fun debugging why some code randomly
produces fatal errors... Debugging PHP is fun enough without quantum
entanglement-like effects :)
The reason why I'm picking it up again is some feedback I received for the
explicit call-time send-by-ref proposal. The main objection seems to be
that the feature has limited usefulness if it's optional rather than
required, because you still can't be sure that something is a by-value
pass, just because no & is present. At the same time, we can't make this
required anytime soon due to the large BC impact.
Where "soon" means "for all practical purposes, forever, unless we stop
calling that new thing PHP", IMO.
Namespace-scoped declares are perfectly suited to resolve this problem. We
I don't think so. First of all, I don't think, of course, that this
problem needs to be solved by adding more complexity to save a purely
cosmetic feature. But second of all, I don't think global hidden context
that could change at a distance how the code is interpreted is a good
idea regardless of whether it solves the issues with send-by-ref.
--
Stas Malyshev
smalyshev@gmail.com
On Tue, Dec 12, 2017 at 8:46 AM, Stanislav Malyshev smalyshev@gmail.com
wrote:
Hi!
The idea is to allow specifying declare directives for a whole library or
project using:namespace_declare('Vendor\Lib', ['strict_types' => 1]);
I am not sure I like this. Namespace is a prefix to a class name.
Anybody can declare a class with any name, and the side-effect that they
would inherit some context, which is completely invisible and would
magically exist somewhere globally, does not seem like a good idea to
me. Moreover, what if something - like older version of the same library
or test or something like that - would have different idea about what
that global state should be? How nice would it be if a piece of
unrelated code could completely change how my code is interpreted? How
nice would it be if whether it works or not would depend on in which
order classes were loaded in this particular request?
The way PHP works, it's not possible to have two versions of a library
loaded at the same time. There are projects like
https://github.com/humbug/php-scoper to allow loading a library multiple
times, which work by prefixing all namespaces. Of course, in this case
namespace_declares() would also be applied to different namespaces and
there will be no interference.
There is no dependence on loading order. The implementation is careful to
ensure that the used declare state is consistent. It's not possible to call
namespace_declare() twice on the same namespace. It's not possible to first
load some files from a namespace, do the namespace_declare() call and then
load some more files. If a namespace_declare() call succeeds without
throwing an error, then that is the ground truth, without any dependence on
order or other calls.
Hidden global context has the same smell as php.ini settings, and for
the same reason - but this, as far as I can see, will also be hidden and
depending on file loading order, class loading order, etc. which in big
applications can lead to a lot of fun debugging why some code randomly
produces fatal errors... Debugging PHP is fun enough without quantum
entanglement-like effects :)
As said above, the implementation makes sure that all quantum state is
collapsed ;) The only possible mistake that can occur is that the
namespace_declare() call doesn't happen at all, but anything depending on
loading order or conflicting calls is not possible.
The big issue with ini settings is (mostly) not the "hidden" part, it's the
"global" part. Ini settings that change language behavior are tabu because
they apply to everything, so no library can assume any particular ini
configuration. Namespace-scoped declares explicitly avoid this. A library
can namespace_declare() it's configuration and be sure that this is the
configuration it's going to get, at the same time not interfering with any
other library or code that uses a different configuration.
The reason why I'm picking it up again is some feedback I received for the
explicit call-time send-by-ref proposal. The main objection seems to be
that the feature has limited usefulness if it's optional rather than
required, because you still can't be sure that something is a by-value
pass, just because no & is present. At the same time, we can't make this
required anytime soon due to the large BC impact.Where "soon" means "for all practical purposes, forever, unless we stop
calling that new thing PHP", IMO.Namespace-scoped declares are perfectly suited to resolve this problem.
WeI don't think so. First of all, I don't think, of course, that this
problem needs to be solved by adding more complexity to save a purely
cosmetic feature. But second of all, I don't think global hidden context
that could change at a distance how the code is interpreted is a good
idea regardless of whether it solves the issues with send-by-ref.
I haven't thought too carefully about whether having an option for the
explicit-send-by-ref feature specifically would be beneficial, but I
think it's very important to at least have the option on the table. Too
many issues in PHP cannot be solved for reasons of backwards-compatibility.
We need to have some way to evolve the language without BC breaks, and I
think namespace-declares are an elegant way to do this.
Regards,
Nikita
Hi!
There is no dependence on loading order. The implementation is careful
to ensure that the used declare state is consistent. It's not possible
to call namespace_declare() twice on the same namespace. It's not
possible to first load some files from a namespace, do the
namespace_declare() call and then load some more files. If a
This means that namespace_declare can be only in one file, and if any
mention of any namespace class has been made before that file has been
loaded, then the declare would fail. That is loading order dependency -
if A.php contains namespace_declare and B.php contains another class of
the same namespace, then order (A, B) works but order (B, A) does not.
The big issue with ini settings is (mostly) not the "hidden" part, it's
the "global" part. Ini settings that change language behavior are tabu
Exactly. And this proposal adds another global state, which is also
invisible, so figuring out what the state is when debugging is... fun.
It's better than php.ini as it's "namespaced php.ini" but still suffers
from the same problems within the namespace (and namespaces can be
pretty big).
this. A library can namespace_declare() it's configuration and be sure
that this is the configuration it's going to get, at the same time not
interfering with any other library or code that uses a different
configuration.
This assumes each namespace is homogeneous code always belonging to the
same library and nothing is every added to that namespace. This is not
always the case.
--
Stas Malyshev
smalyshev@gmail.com
I agree with all of Stanislav's emails in this thread so far.
On Tue, Dec 12, 2017 at 8:46 AM, Stanislav Malyshev smalyshev@gmail.com
wrote:Hi!
The idea is to allow specifying declare directives for a whole library or
project using:namespace_declare('Vendor\Lib', ['strict_types' => 1]);
I am not sure I like this. Namespace is a prefix to a class name.
Anybody can declare a class with any name, and the side-effect that they
would inherit some context, which is completely invisible and would
magically exist somewhere globally, does not seem like a good idea to
me. Moreover, what if something - like older version of the same library
or test or something like that - would have different idea about what
that global state should be? How nice would it be if a piece of
unrelated code could completely change how my code is interpreted? How
nice would it be if whether it works or not would depend on in which
order classes were loaded in this particular request?The way PHP works, it's not possible to have two versions of a library
loaded at the same time.
Really?
PHP does not even know what a "library" is. PHP sees files,
directories and namespaces. But it does not know how to conceptualize
any of this as a "library".
With Composer you get the notion of a "package".
In general, Composer would prevent you from using different versions
of the same package.
But you could manually download two versions of a package, and wire up
the class loader in a way that it would load some classes from one
version, and some classes from another version.
E.g. if a class does not exist in version 2, load the class from
version 1 instead.
PHP as a language should not assume that someone is using Composer correctly.
And even if we avoid two package versions coexisting: There could
easily be two distinct packages that use the same namespace.
We could discuss if this is a good idea, but it should not be the job
of PHP as a language to make this situation difficult.
There is no dependence on loading order. The implementation is careful to
ensure that the used declare state is consistent. It's not possible to call
namespace_declare() twice on the same namespace. It's not possible to first
load some files from a namespace, do the namespace_declare() call and then
load some more files. If a namespace_declare() call succeeds without
throwing an error, then that is the ground truth, without any dependence on
order or other calls.
So by "is not possible", in fact you mean "will trigger an error".
I imagine with Composer we would have to agree on a canonical file
name where a namespace_declare() would be found.
Maybe something like in src/Acme/Animal.namespace.php.
The class loader would then have to make sure that this file is
included before the first class from that namespace is included.
Or alternatively, Composer init script would have to include all such
files at the beginning of the process.
If Composer (or whichever tool one wants to use) would include class
file src/Acme/Animal/Cat.php without prior inclusion of the
Animal.namespace.php, the class file would be interpreted without the
desired setting.
If the process then continues without ever including
Animal.namespace.php, it will silently misbehave.
If, however, Animal.namespace.php is included some time later in the
process, then it would notice that something went wrong, and trigger
an error.
I haven't thought too carefully about whether having an option for the
explicit-send-by-ref feature specifically would be beneficial, but I
think it's very important to at least have the option on the table. Too
many issues in PHP cannot be solved for reasons of backwards-compatibility.
We need to have some way to evolve the language without BC breaks, and I
think namespace-declares are an elegant way to do this.
So if you want a setting for explicit-send-by-ref, why not do this per
file, as we already do for strict_types?
If at some day in the future we find that the declares become too
verbose, we could bundle multiple declares into a new setting.
E.g. something like "declare(php=8.1);" to combine all the declares
that would be considered default in PHP 8.1.
Or introduce some other shortcut like "<?php.8.1" instead of "<?php"
opening tag.
2017-12-13 1:16 GMT+01:00 Andreas Hennings andreas@dqxtech.net:
I agree with all of Stanislav's emails in this thread so far.
On Tue, Dec 12, 2017 at 8:46 AM, Stanislav Malyshev <smalyshev@gmail.com
wrote:
Hi!
The idea is to allow specifying declare directives for a whole
library or
project using:namespace_declare('Vendor\Lib', ['strict_types' => 1]);
I am not sure I like this. Namespace is a prefix to a class name.
Anybody can declare a class with any name, and the side-effect that they
would inherit some context, which is completely invisible and would
magically exist somewhere globally, does not seem like a good idea to
me. Moreover, what if something - like older version of the same library
or test or something like that - would have different idea about what
that global state should be? How nice would it be if a piece of
unrelated code could completely change how my code is interpreted? How
nice would it be if whether it works or not would depend on in which
order classes were loaded in this particular request?The way PHP works, it's not possible to have two versions of a library
loaded at the same time.Really?
PHP does not even know what a "library" is. PHP sees files,
directories and namespaces. But it does not know how to conceptualize
any of this as a "library".With Composer you get the notion of a "package".
In general, Composer would prevent you from using different versions
of the same package.
But you could manually download two versions of a package, and wire up
the class loader in a way that it would load some classes from one
version, and some classes from another version.
E.g. if a class does not exist in version 2, load the class from
version 1 instead.PHP as a language should not assume that someone is using Composer
correctly.And even if we avoid two package versions coexisting: There could
easily be two distinct packages that use the same namespace.
We could discuss if this is a good idea, but it should not be the job
of PHP as a language to make this situation difficult.There is no dependence on loading order. The implementation is careful to
ensure that the used declare state is consistent. It's not possible to
call
namespace_declare() twice on the same namespace. It's not possible to
first
load some files from a namespace, do the namespace_declare() call and
then
load some more files. If a namespace_declare() call succeeds without
throwing an error, then that is the ground truth, without any dependence
on
order or other calls.So by "is not possible", in fact you mean "will trigger an error".
I imagine with Composer we would have to agree on a canonical file
name where a namespace_declare() would be found.
Maybe something like in src/Acme/Animal.namespace.php.The class loader would then have to make sure that this file is
included before the first class from that namespace is included.
Or alternatively, Composer init script would have to include all such
files at the beginning of the process.If Composer (or whichever tool one wants to use) would include class
file src/Acme/Animal/Cat.php without prior inclusion of the
Animal.namespace.php, the class file would be interpreted without the
desired setting.
If the process then continues without ever including
Animal.namespace.php, it will silently misbehave.
If, however, Animal.namespace.php is included some time later in the
process, then it would notice that something went wrong, and trigger
an error.
If we're going to introduce someday a namespace file, then IMO it should
not be putted outside namespace folder.
For eg class Acme\Animal\Cat in src/Acme/Animal/Cat.php should have
namespace file in src/Acme/Aniimal/namespace.php
or even more src/Acme/Animal/ns.php
Why? Because users use PSR-4 so then they're src folder looks more like:
src/Cat.php <-- class Acme\Animal\Cat
src/ns.php <-- that should be then a place for namespace declare or even
function and constants.
Such namespace file can be a good place for namespace function and
constants declaration.
Also I think there is no need for another global function named
namespace_declare
if we had namespace file
then we can utilise declare for that.
Lets imagine such syntax:
// src/Acme/Animal/ns.php
<?php
namespace Acme\Animal declare(strict_types=1,another_option=0);
const CAT = 1;
function createCat() : Cat {}
A good reason for that is that we're not using namespace as a string in
function call which is more IDE friendly to refactor.
There is another good reason for that - some code generators/container
compilers etc. whatever else
uses one file for more than one class that means there would be still an
option to pack few namespaces in one
separate file like for. eg:
<?php
namespace Acme\Animal declare(strict_types=1) {
class Cat {}
}
namespace Another\Library { // <-- there is no declare for this namespace
class SomeClass {}
}
These are just my thoughts and they can be completely nonsense.
I think it might be also a good place to provide more info in a future.
I know PHP is not Java9 and I'm gratefull for that, but IMHO sometimes
there are good concepts,
like module info in module-info.java file with module exports and requires
and info about what it provides at all.
I haven't thought too carefully about whether having an option for the
explicit-send-by-ref feature specifically would be beneficial, but I
think it's very important to at least have the option on the table. Too
many issues in PHP cannot be solved for reasons of
backwards-compatibility.
We need to have some way to evolve the language without BC breaks, and
I
think namespace-declares are an elegant way to do this.So if you want a setting for explicit-send-by-ref, why not do this per
file, as we already do for strict_types?If at some day in the future we find that the declares become too
verbose, we could bundle multiple declares into a new setting.
E.g. something like "declare(php=8.1);" to combine all the declares
that would be considered default in PHP 8.1.Or introduce some other shortcut like "<?php.8.1" instead of "<?php"
opening tag.--
--
regards / pozdrawiam,
Michał Brzuchalski
about.me/brzuchal
brzuchalski.com
If we're going to introduce someday a namespace file, then IMO it should not
be putted outside namespace folder.
For eg class Acme\Animal\Cat in src/Acme/Animal/Cat.php should have
namespace file in src/Acme/Aniimal/namespace.php
or even more src/Acme/Animal/ns.php
Why? Because users use PSR-4 so then they're src folder looks more like:
src/Cat.php <-- class Acme\Animal\Cat
src/ns.php <-- that should be then a place for namespace declare or even
function and constants.
You are right, my previous proposal src/Acme/Animal.namespace.php
would not work universally.
But your proposal, src/Acme/Animal/ns.php clashes with the class file
for class \Acme\Animal\ns.
We would need something other than NAME.php.
E.g. src/Acme/Animal/ns.inc.php
But then Composer would still need to make sure that this file is
always included before any class files from this directory.
On language level we cannot assume that Composer is being used, and
that it is being used correctly.
So again this would be fragile.
Such namespace file can be a good place for namespace function and constants
declaration.
Also I think there is no need for another global function named
namespace_declare
if we had namespace file
then we can utilise declare for that.
Lets imagine such syntax:// src/Acme/Animal/ns.php
<?phpnamespace Acme\Animal declare(strict_types=1,another_option=0);
const CAT = 1;
function createCat() : Cat {}
This means you are changing the meaning of existing declare() to apply
to the entire namespace?
Or to the entire directory?
Or maybe the difference here is that there is no semicolon directly
after the namespace declaration?
I am not convinced by this syntax.
But even if we would find a good syntax, the behavioral problems
pointed out by Stanislav still apply.
2017-12-13 5:24 GMT+01:00 Andreas Hennings andreas@dqxtech.net:
On 13 December 2017 at 05:04, Michał Brzuchalski michal@brzuchalski.com
wrote:If we're going to introduce someday a namespace file, then IMO it should
not
be putted outside namespace folder.
For eg class Acme\Animal\Cat in src/Acme/Animal/Cat.php should have
namespace file in src/Acme/Aniimal/namespace.php
or even more src/Acme/Animal/ns.php
Why? Because users use PSR-4 so then they're src folder looks more like:
src/Cat.php <-- class Acme\Animal\Cat
src/ns.php <-- that should be then a place for namespace declare or even
function and constants.You are right, my previous proposal src/Acme/Animal.namespace.php
would not work universally.But your proposal, src/Acme/Animal/ns.php clashes with the class file
for class \Acme\Animal\ns.We would need something other than NAME.php.
E.g. src/Acme/Animal/ns.inc.phpBut then Composer would still need to make sure that this file is
always included before any class files from this directory.
On language level we cannot assume that Composer is being used, and
that it is being used correctly.So again this would be fragile.
Such namespace file can be a good place for namespace function and
constants
declaration.
Also I think there is no need for another global function named
namespace_declare
if we had namespace file
then we can utilise declare for that.
Lets imagine such syntax:// src/Acme/Animal/ns.php
<?phpnamespace Acme\Animal declare(strict_types=1,another_option=0);
const CAT = 1;
function createCat() : Cat {}This means you are changing the meaning of existing declare() to apply
to the entire namespace?
Or to the entire directory?
To entire namespace just like:
<?php declare(strict_types=0);
namespace_declare('Acme\Animal', [
'strict_types' => 1,
'dynamic_object_properties' => 0,
...
]);
namespace Acme\Animal declare(
strict_types=1,
dynamic_object_properties=0
); // <-- this works same as namespace_declare call above
namespace Acme\Machines {
// here we have strict_types=0 turned off
}
Or maybe the difference here is that there is no semicolon directly
after the namespace declaration?I am not convinced by this syntax.
But even if we would find a good syntax, the behavioral problems
pointed out by Stanislav still apply.
--
regards / pozdrawiam,
Michał Brzuchalski
about.me/brzuchal
brzuchalski.com
2017-12-13 5:38 GMT+01:00 Michał Brzuchalski michal@brzuchalski.com:
2017-12-13 5:24 GMT+01:00 Andreas Hennings andreas@dqxtech.net:
On 13 December 2017 at 05:04, Michał Brzuchalski michal@brzuchalski.com
wrote:If we're going to introduce someday a namespace file, then IMO it
should not
be putted outside namespace folder.
For eg class Acme\Animal\Cat in src/Acme/Animal/Cat.php should have
namespace file in src/Acme/Aniimal/namespace.php
or even more src/Acme/Animal/ns.php
Why? Because users use PSR-4 so then they're src folder looks more like:
src/Cat.php <-- class Acme\Animal\Cat
src/ns.php <-- that should be then a place for namespace declare or even
function and constants.You are right, my previous proposal src/Acme/Animal.namespace.php
would not work universally.But your proposal, src/Acme/Animal/ns.php clashes with the class file
for class \Acme\Animal\ns.We would need something other than NAME.php.
E.g. src/Acme/Animal/ns.inc.php
Actually not true. namespace
keyword is reserved and none class can have
such name.
This means this example couses a syntax error:
<?php
namespace Acme\Animals;
class namespace {}
That why we can assume we can utilise namespace.php file name.
And also why not trying to include it on autoload call?
For eg.
<?php
new Acme\Animal\Cat(); // tries to load $file = "src/Acme/Animal/Cat.php"
// but prevoiusly tries to load
require_once dirname($file) . DIRECTORY_SEPARATOR
. 'namespace.php';
It's bad because it';s magic, but the namespace.php
filename is still
available to use.
But then Composer would still need to make sure that this file is
always included before any class files from this directory.
On language level we cannot assume that Composer is being used, and
that it is being used correctly.So again this would be fragile.
Such namespace file can be a good place for namespace function and
constants
declaration.
Also I think there is no need for another global function named
namespace_declare
if we had namespace file
then we can utilise declare for that.
Lets imagine such syntax:// src/Acme/Animal/ns.php
<?phpnamespace Acme\Animal declare(strict_types=1,another_option=0);
const CAT = 1;
function createCat() : Cat {}This means you are changing the meaning of existing declare() to apply
to the entire namespace?
Or to the entire directory?To entire namespace just like:
<?php declare(strict_types=0);
namespace_declare('Acme\Animal', [
'strict_types' => 1,
'dynamic_object_properties' => 0,
...
]);namespace Acme\Animal declare(
strict_types=1,
dynamic_object_properties=0
); // <-- this works same as namespace_declare call abovenamespace Acme\Machines {
// here we have strict_types=0 turned off
}Or maybe the difference here is that there is no semicolon directly
after the namespace declaration?I am not convinced by this syntax.
But even if we would find a good syntax, the behavioral problems
pointed out by Stanislav still apply.--
regards / pozdrawiam,Michał Brzuchalski
about.me/brzuchal
brzuchalski.com
--
regards / pozdrawiam,
Michał Brzuchalski
about.me/brzuchal
brzuchalski.com
2017-12-13 6:04 GMT+01:00 Michał Brzuchalski michal@brzuchalski.com:
2017-12-13 5:38 GMT+01:00 Michał Brzuchalski michal@brzuchalski.com:
2017-12-13 5:24 GMT+01:00 Andreas Hennings andreas@dqxtech.net:
On 13 December 2017 at 05:04, Michał Brzuchalski michal@brzuchalski.com
wrote:If we're going to introduce someday a namespace file, then IMO it
should not
be putted outside namespace folder.
For eg class Acme\Animal\Cat in src/Acme/Animal/Cat.php should have
namespace file in src/Acme/Aniimal/namespace.php
or even more src/Acme/Animal/ns.php
Why? Because users use PSR-4 so then they're src folder looks more
like:
src/Cat.php <-- class Acme\Animal\Cat
src/ns.php <-- that should be then a place for namespace declare or
even
function and constants.You are right, my previous proposal src/Acme/Animal.namespace.php
would not work universally.But your proposal, src/Acme/Animal/ns.php clashes with the class file
for class \Acme\Animal\ns.We would need something other than NAME.php.
E.g. src/Acme/Animal/ns.inc.phpActually not true.
namespace
keyword is reserved and none class can have
such name.
This means this example couses a syntax error:<?php
namespace Acme\Animals;
class namespace {}That why we can assume we can utilise namespace.php file name.
And also why not trying to include it on autoload call?
For eg.
<?phpnew Acme\Animal\Cat(); // tries to load $file = "src/Acme/Animal/Cat.php"
// but prevoiusly tries to load
require_once dirname($file) .DIRECTORY_SEPARATOR
. 'namespace.php';It's bad because it';s magic, but the
namespace.php
filename is still
available to use.
Andreas, we're touching namespaces which is a hard subject, but if I could
fly away with my thoughts
I'd propose to introduce something called for eg. a package and then
divide it's name in class/function/const name with a single colon, for eg.
Acme:Animal\Cat
which gives additional information about package which then declares
something and may be
a good start for future scoped declarations.
I've prepared a short gist to illustrate that
https://gist.github.com/brzuchal/352ffce2717648f0d43f2d5a0c4bfb7b
This solution doesn't require usage of Composer, but needs to pass an
aotuloader function a type to load.
There was a proposal on internal some time ago to pass additional parameter
to load function.
But then Composer would still need to make sure that this file is
always included before any class files from this directory.
On language level we cannot assume that Composer is being used, and
that it is being used correctly.So again this would be fragile.
Such namespace file can be a good place for namespace function and
constants
declaration.
Also I think there is no need for another global function named
namespace_declare
if we had namespace file
then we can utilise declare for that.
Lets imagine such syntax:// src/Acme/Animal/ns.php
<?phpnamespace Acme\Animal declare(strict_types=1,another_option=0);
const CAT = 1;
function createCat() : Cat {}This means you are changing the meaning of existing declare() to apply
to the entire namespace?
Or to the entire directory?To entire namespace just like:
<?php declare(strict_types=0);
namespace_declare('Acme\Animal', [
'strict_types' => 1,
'dynamic_object_properties' => 0,
...
]);namespace Acme\Animal declare(
strict_types=1,
dynamic_object_properties=0
); // <-- this works same as namespace_declare call abovenamespace Acme\Machines {
// here we have strict_types=0 turned off
}Or maybe the difference here is that there is no semicolon directly
after the namespace declaration?I am not convinced by this syntax.
But even if we would find a good syntax, the behavioral problems
pointed out by Stanislav still apply.--
regards / pozdrawiam,Michał Brzuchalski
about.me/brzuchal
brzuchalski.com--
regards / pozdrawiam,Michał Brzuchalski
about.me/brzuchal
brzuchalski.com
--
regards / pozdrawiam,
Michał Brzuchalski
about.me/brzuchal
brzuchalski.com
Andreas, we're touching namespaces which is a hard subject, but if I could
fly away with my thoughts
I'd propose to introduce something called for eg. a package
My thoughts were actually going along the same lines: basically, the
current implementation of namespaces is, I think by design, very
conservative in what a namespace represents. A namespace doesn't have
any identity, and doesn't have any codified structure, it's just a
shorthand for referring to similarly named classes (plus functions and
constants).
There are several things that I think would feel more natural with
"packages" than namespaces as they exist today:
- Declare directives, as discussed here
- Visibility modifiers, e.g. a "private class", accessible only within
its package - Per-package autoloaders, that only get called for classes in that
package, rather than a global autoloader which parses out the prefixes
it's interested in - An autoloader callback that fires once for each package, to setup
these options
Another difference is that namespaces tend to form deep hierarchies, but
you're unlikely to set options at every level of the hierarchy. For
instance, you probably don't want to set strict_types on for
Acme\MyPackage\Input but off for Acme\MyPackage\Output. So a separate
syntax to mark which level is the "package" would reduce the number of
places a setting could be set, which would reduce the number of places
you'd need to look - a bit like having Apache settings in a VirtualHost
for the whole site, rather than .htaccess files in every directory.
All that being said, I'm not 100% convinced this is solving a real
problem. Yes, the option has to be set in every file, but that's because
it effects the way that file is compiled, and the compiler sees one file
at a time. The same applies to the "namespace" directive, which you
might otherwise set against a particular directory. I don't see a
pressing need to add the complexity.
Regards,
--
Rowan Collins
[IMSoP]
""Michal Brzuchalski"" wrote in message
news:CABdc3WpomNLz+vX_m0B0wQ3uCiMiw8xw4Ea_sGD-PTDGfV-PbA@mail.gmail.com...
<snip> > >Why? Because users use PSR-4 so then they're src folder looks more like: ? <snip>2017-12-13 1:16 GMT+01:00 Andreas Hennings andreas@dqxtech.net:
You are assuming that everybody is using PSR-4. That is a wrong assumption
to make.
--
Tony Marston
13.12.2017 11:44 "Tony Marston" TonyMarston@hotmail.com napisał(a):
""Michal Brzuchalski"" wrote in message news:CABdc3WpomNLz+vX_m0B0wQ3u
CiMiw8xw4Ea_sGD-PTDGfV-PbA@mail.gmail.com...
2017-12-13 1:16 GMT+01:00 Andreas Hennings andreas@dqxtech.net:
<snip>
Why? Because users use PSR-4 so then they're src folder looks more like:
?
<snip>
You are assuming that everybody is using PSR-4. That is a wrong assumption
to make.
I didn't say everybody at all! Please read carefully.
--
Tony Marston
""Michal Brzuchalski"" wrote in message
news:CABdc3Wrz8qu_hGsBTjGbWwcT8YpLxgChONeE9NiJKWcDEruySw@mail.gmail.com...
13.12.2017 11:44 "Tony Marston" TonyMarston@hotmail.com napisal(a):
""Michal Brzuchalski"" wrote in message news:CABdc3WpomNLz+vX_m0B0wQ3u
CiMiw8xw4Ea_sGD-PTDGfV-PbA@mail.gmail.com...2017-12-13 1:16 GMT+01:00 Andreas Hennings andreas@dqxtech.net:
<snip>Why? Because users use PSR-4 so then they're src folder looks more like:
?
<snip>You are assuming that everybody is using PSR-4. That is a wrong assumption
to make.I didn't say everybody at all! Please read carefully.
I DID read carefully. You wrote "users use PSR-4" and not "those users who
use PSR-4". You did not specify a subset of users, so this implies all
users.
--
Tony Marston
"Andreas Hennings" wrote in message
news:CAH0Uv3FnYf_c7in4_6AmDO5pUZHsgU0m5scjU5oRz2kTAJ=+bw@mail.gmail.com...
<snip> > >PHP as a language should not assume that someone is using Composer >correctly. >I agree with all of Stanislav's emails in this thread so far.
On Tue, Dec 12, 2017 at 8:46 AM, Stanislav Malyshev smalyshev@gmail.com
wrote:
Or even using Composer at all.
--
Tony Marston
Some time ago I introduced the following proposal for namespace-scoped
declares:https://wiki.php.net/rfc/namespace_scoped_declares
The idea is to allow specifying declare directives for a whole library or
project using:namespace_declare('Vendor\Lib', ['strict_types' => 1]);
I've finally gotten around to implementing this proposal (
https://github.com/php/php-src/pull/2972) and would like to move forward
with it.
Generally I'm not keen on letting the language diverge via whatever
mechanism, but that has already happened and there seems to be some
further need, and the namespace scoped declares appear to be preferable
to per-file declares or even ini settings.
What I don't like about the present proposal is that it introduces a
proper function instead of a language construct. Is there a particular
reason for this design decision? Couldn't we add the namespace scoped
declares to the namespace declaration directly, e.g.
namespace Foo declare strict_types=1;
--
Christoph M. Becker
Some time ago I introduced the following proposal for namespace-scoped
declares:https://wiki.php.net/rfc/namespace_scoped_declares
The idea is to allow specifying declare directives for a whole library or
project using:namespace_declare('Vendor\Lib', ['strict_types' => 1]);
I've finally gotten around to implementing this proposal (
https://github.com/php/php-src/pull/2972) and would like to move forward
with it.The reason why I'm picking it up again is some feedback I received for the
explicit call-time send-by-ref proposal. The main objection seems to be
that the feature has limited usefulness if it's optional rather than
required, because you still can't be sure that something is a by-value
pass, just because no & is present. At the same time, we can't make this
required anytime soon due to the large BC impact.Namespace-scoped declares are perfectly suited to resolve this problem. We
can introduce a require_explicit_send_by_ref declare directive to make the
call-site annotation required, and libraries/projects can easily opt-in to
it using namespace_declare(). There would be no BC impact, while at the
same time projects could benefit from the additional clarity and
performance improvements immediately.
Thanks for the proposal.
While it seems comfortable for the user, and I understand the point
you're trying to solve somehow, it can be a nightmare for the VM, the
developer, and the user.
I've few remarks and/or questions:
-
When parsing a file, the way the VM has to interprete/execute the file
depends on a runtime configuration defined in another file. It makes
things more implicit, and that's not good. -
It can also be a nightmare for the developer. The behavior of their
library can be changed by another library because there is no
restriction about the location or usage ofnamespace_declare
. If at
leastnamespace_declare
would only apply to the current namespace,
it might be better. -
If
namespace_declare
is called twice for the same namespace, an
error is raised, OK. It's easy to break someone's code by registering a
file in an autoloader to load first, and callnamespace_declare
for
that file. What the error will look like? It's important to prompt the
correct culprit to the user. Any strategy to find which one is the culprit? -
As you said in the RFC in the Proliferation of declare directives
Section, it's not a good thing for the language to introduce more and
more directives. PHP is living a time where it makes good things easier
to do, and bad things harder to do. Everything I can imagine with
namespace_declare
is definitively not good for the language, the VM,
and the ecosystem. Introducing astrict
mode for the language is
definitively a good thing to progressively make PHP stricter, yes, but I
don't see a real need or a real motiviation behindnamespace_declare
,
I for one see only dangers.
So I'm sorry to say that —right now— I'm totally oppose to this RFC :-).
Cheers.
-Ivan.
Le lun. 11 déc. 2017 à 14:44, Nikita Popov nikita.ppv@gmail.com a écrit :
Some time ago I introduced the following proposal for namespace-scoped
declares:https://wiki.php.net/rfc/namespace_scoped_declares
The idea is to allow specifying declare directives for a whole library or
project using:namespace_declare('Vendor\Lib', ['strict_types' => 1]);
I've finally gotten around to implementing this proposal (
https://github.com/php/php-src/pull/2972) and would like to move forward
with it.The reason why I'm picking it up again is some feedback I received for the
explicit call-time send-by-ref proposal. The main objection seems to be
that the feature has limited usefulness if it's optional rather than
required, because you still can't be sure that something is a by-value
pass, just because no & is present. At the same time, we can't make this
required anytime soon due to the large BC impact.Namespace-scoped declares are perfectly suited to resolve this problem. We
can introduce a require_explicit_send_by_ref declare directive to make the
call-site annotation required, and libraries/projects can easily opt-in to
it using namespace_declare(). There would be no BC impact, while at the
same time projects could benefit from the additional clarity and
performance improvements immediately.
I've read discussions about the notion of a "package" and the way we should
define its boundaries.
What about the following?
Individual files could declare their package using this style:
<?php declare(package=MyVendor\MyPackage);
That would be enough to group a set of files together and make them share
eg some private classes, some optional PHP behaviors, etc.
The right side "MyVendor\MyPackage" would also be a FQCN that PHP would
autoload as a regular class. The corresponding class would then be the
place where ppl would declare the engine behavior they want for their
package (strict types, etc). To enforce this, the engine could require that
the "MyPackage" class implements some interface/extend some base abstract
class.
Of course, one could hijack a package and declare an unrelated file as part
of it, but I don't think that's an issue: the situation is the same as for
namespaces, where one can hijack a third party vendor namespace. In
practice, it proved not being an issue, and the original author's intent is
clear: "this is my namespace/package, if you mess with it, fine, but you're
on your own".
Nicolas
On Mon, Aug 12, 2019 at 10:17 AM Nicolas Grekas <
nicolas.grekas+php@gmail.com> wrote:
Le lun. 11 déc. 2017 à 14:44, Nikita Popov nikita.ppv@gmail.com a
écrit :Some time ago I introduced the following proposal for namespace-scoped
declares:https://wiki.php.net/rfc/namespace_scoped_declares
The idea is to allow specifying declare directives for a whole library or
project using:namespace_declare('Vendor\Lib', ['strict_types' => 1]);
I've finally gotten around to implementing this proposal (
https://github.com/php/php-src/pull/2972) and would like to move forward
with it.The reason why I'm picking it up again is some feedback I received for the
explicit call-time send-by-ref proposal. The main objection seems to be
that the feature has limited usefulness if it's optional rather than
required, because you still can't be sure that something is a by-value
pass, just because no & is present. At the same time, we can't make this
required anytime soon due to the large BC impact.Namespace-scoped declares are perfectly suited to resolve this problem. We
can introduce a require_explicit_send_by_ref declare directive to make the
call-site annotation required, and libraries/projects can easily opt-in to
it using namespace_declare(). There would be no BC impact, while at the
same time projects could benefit from the additional clarity and
performance improvements immediately.I've read discussions about the notion of a "package" and the way we
should define its boundaries.
What about the following?Individual files could declare their package using this style:
<?php declare(package=MyVendor\MyPackage);That would be enough to group a set of files together and make them share
eg some private classes, some optional PHP behaviors, etc.The right side "MyVendor\MyPackage" would also be a FQCN that PHP would
autoload as a regular class. The corresponding class would then be the
place where ppl would declare the engine behavior they want for their
package (strict types, etc). To enforce this, the engine could require that
the "MyPackage" class implements some interface/extend some base abstract
class.Of course, one could hijack a package and declare an unrelated file as
part of it, but I don't think that's an issue: the situation is the same as
for namespaces, where one can hijack a third party vendor namespace. In
practice, it proved not being an issue, and the original author's intent is
clear: "this is my namespace/package, if you mess with it, fine, but you're
on your own".Nicolas
FTR I've created a draft-implementation for a package system here:
https://github.com/php/php-src/pull/4490
It uses a slightly different approach in that it keeps the package name a
string (that should usually match the Composer package name) and uses a
function to register the package.
The main annoyance is that this requires declaring the package in every
file, something I would like to avoid. An alternative I played with is to
allow specifying the package at include time, which would allow the
autoloader to specify which package a file is part. However, while this is
more ergonomic for the user, I'm afraid that this will make static analysis
& IDE scenarios problematic, because they will not be able to easily know
what the package is in cases that fall outside convention. So in the end,
an explicit per-file package declaration may be the best we can do.
Nikita
On Mon, Aug 12, 2019 at 10:17 AM Nicolas Grekas <
nicolas.grekas+php@gmail.com> wrote:Le lun. 11 déc. 2017 à 14:44, Nikita Popov nikita.ppv@gmail.com a
écrit :Some time ago I introduced the following proposal for namespace-scoped
declares:https://wiki.php.net/rfc/namespace_scoped_declares
The idea is to allow specifying declare directives for a whole library or
project using:namespace_declare('Vendor\Lib', ['strict_types' => 1]);
I've finally gotten around to implementing this proposal (
https://github.com/php/php-src/pull/2972) and would like to move forward
with it.The reason why I'm picking it up again is some feedback I received for the
explicit call-time send-by-ref proposal. The main objection seems to be
that the feature has limited usefulness if it's optional rather than
required, because you still can't be sure that something is a by-value
pass, just because no & is present. At the same time, we can't make this
required anytime soon due to the large BC impact.Namespace-scoped declares are perfectly suited to resolve this problem. We
can introduce a require_explicit_send_by_ref declare directive to make the
call-site annotation required, and libraries/projects can easily opt-in to
it using namespace_declare(). There would be no BC impact, while at the
same time projects could benefit from the additional clarity and
performance improvements immediately.I've read discussions about the notion of a "package" and the way we
should define its boundaries.
What about the following?Individual files could declare their package using this style:
<?php declare(package=MyVendor\MyPackage);That would be enough to group a set of files together and make them share
eg some private classes, some optional PHP behaviors, etc.The right side "MyVendor\MyPackage" would also be a FQCN that PHP would
autoload as a regular class. The corresponding class would then be the
place where ppl would declare the engine behavior they want for their
package (strict types, etc). To enforce this, the engine could require that
the "MyPackage" class implements some interface/extend some base abstract
class.Of course, one could hijack a package and declare an unrelated file as
part of it, but I don't think that's an issue: the situation is the same as
for namespaces, where one can hijack a third party vendor namespace. In
practice, it proved not being an issue, and the original author's intent is
clear: "this is my namespace/package, if you mess with it, fine, but you're
on your own".Nicolas
FTR I've created a draft-implementation for a package system here:
https://github.com/php/php-src/pull/4490It uses a slightly different approach in that it keeps the package name a
string (that should usually match the Composer package name) and uses a
function to register the package.The main annoyance is that this requires declaring the package in every
file, something I would like to avoid. An alternative I played with is to
allow specifying the package at include time, which would allow the
autoloader to specify which package a file is part. However, while this is
more ergonomic for the user, I'm afraid that this will make static analysis
& IDE scenarios problematic, because they will not be able to easily know
what the package is in cases that fall outside convention. So in the end,
an explicit per-file package declaration may be the best we can do.Nikita
Is there some specific benefit to passing an array with name
and declares
keys, over a signature like either
package_declare(‘nikic/php-parser’, strict_types=1, foo=bar);
or even
package_declare('nikic/php-parser’, [‘strict_types’ => 1, ‘foo’ => bar]);
I realise this is the epitome of bike shedding, it just seems like a non-obvious choice (to me at least) to accept a specifically structured array?
Cheers
Stephen
Hi,
Am 12.08.19 um 10:26 schrieb Nikita Popov:
On Mon, Aug 12, 2019 at 10:17 AM Nicolas Grekas <
nicolas.grekas+php@gmail.com> wrote:Le lun. 11 déc. 2017 à 14:44, Nikita Popov nikita.ppv@gmail.com a
écrit :Some time ago I introduced the following proposal for namespace-scoped
declares:https://wiki.php.net/rfc/namespace_scoped_declares
The idea is to allow specifying declare directives for a whole library or
project using:namespace_declare('Vendor\Lib', ['strict_types' => 1]);
I've finally gotten around to implementing this proposal (
https://github.com/php/php-src/pull/2972) and would like to move forward
with it.The reason why I'm picking it up again is some feedback I received for the
explicit call-time send-by-ref proposal. The main objection seems to be
that the feature has limited usefulness if it's optional rather than
required, because you still can't be sure that something is a by-value
pass, just because no & is present. At the same time, we can't make this
required anytime soon due to the large BC impact.Namespace-scoped declares are perfectly suited to resolve this problem. We
can introduce a require_explicit_send_by_ref declare directive to make the
call-site annotation required, and libraries/projects can easily opt-in to
it using namespace_declare(). There would be no BC impact, while at the
same time projects could benefit from the additional clarity and
performance improvements immediately.I've read discussions about the notion of a "package" and the way we
should define its boundaries.
What about the following?Individual files could declare their package using this style:
<?php declare(package=MyVendor\MyPackage);That would be enough to group a set of files together and make them share
eg some private classes, some optional PHP behaviors, etc.The right side "MyVendor\MyPackage" would also be a FQCN that PHP would
autoload as a regular class. The corresponding class would then be the
place where ppl would declare the engine behavior they want for their
package (strict types, etc). To enforce this, the engine could require that
the "MyPackage" class implements some interface/extend some base abstract
class.Of course, one could hijack a package and declare an unrelated file as
part of it, but I don't think that's an issue: the situation is the same as
for namespaces, where one can hijack a third party vendor namespace. In
practice, it proved not being an issue, and the original author's intent is
clear: "this is my namespace/package, if you mess with it, fine, but you're
on your own".Nicolas
FTR I've created a draft-implementation for a package system here:
https://github.com/php/php-src/pull/4490It uses a slightly different approach in that it keeps the package name a
string (that should usually match the Composer package name) and uses a
function to register the package.The main annoyance is that this requires declaring the package in every
file, something I would like to avoid. An alternative I played with is to
allow specifying the package at include time, which would allow the
autoloader to specify which package a file is part. However, while this is
more ergonomic for the user, I'm afraid that this will make static analysis
& IDE scenarios problematic, because they will not be able to easily know
what the package is in cases that fall outside convention. So in the end,
an explicit per-file package declaration may be the best we can do.
I'm not sure if this was discussed/proposed before:
Why not have a concept similar to autoloaders that resolves a given
class name to some declare statements.
That way you could implement a composer based resolver that takes a
class name, (internally) resolves it to a package (based on the
autoloader configuration in composer.json), and returns an array of the
specified declare statements.
Developers do not need to specify a package or any declare statements in
PHP files at all, as PHP (or static analyzers) would be able to ask the
class-name-to-declare-statements resolver which declare statements a PHP
file defines.
Alternatively, you could introduce the concept of a
Package(Specification) class as proposed by Nicolas (but without the
need to extend and implement it in each package). That way the resolver
does not return the array of declare statements but an instance of the
Package(Specification) class that was constructed by the composer-based
resolver dynamically with the declare statements as defined in
composer.json.
Not sure: Perhaps you even do not need a new concept of a resolver but
could extend the concept of autoloaders?
Regards
Thomas
On Mon, Aug 12, 2019 at 10:17 AM Nicolas Grekas <
nicolas.grekas+php@gmail.com> wrote:
I've read discussions about the notion of a "package" and the way we
should define its boundaries.
What about the following?Individual files could declare their package using this style:
<?php declare(package=MyVendor\MyPackage);That would be enough to group a set of files together and make them share
eg some private classes, some optional PHP behaviors, etc.The right side "MyVendor\MyPackage" would also be a FQCN that PHP would
autoload as a regular class. The corresponding class would then be the
place where ppl would declare the engine behavior they want for their
package (strict types, etc). To enforce this, the engine could require that
the "MyPackage" class implements some interface/extend some base abstract
class.Of course, one could hijack a package and declare an unrelated file as
part of it, but I don't think that's an issue: the situation is the same as
for namespaces, where one can hijack a third party vendor namespace. In
practice, it proved not being an issue, and the original author's intent is
clear: "this is my namespace/package, if you mess with it, fine, but you're
on your own".Nicolas
FTR I've created a draft-implementation for a package system here:
https://github.com/php/php-src/pull/4490It uses a slightly different approach in that it keeps the package name a
string (that should usually match the Composer package name) and uses a
function to register the package.The main annoyance is that this requires declaring the package in every
file, something I would like to avoid. An alternative I played with is to
allow specifying the package at include time, which would allow the
autoloader to specify which package a file is part. However, while this is
more ergonomic for the user, I'm afraid that this will make static analysis
& IDE scenarios problematic, because they will not be able to easily know
what the package is in cases that fall outside convention. So in the end,
an explicit per-file package declaration may be the best we can do.Nikita
I don't think declaring the package in each file is necessarily bad. Every language I've worked in either has you declare a package explicitly or implies it off of the file system and you don't get any say in the matter. Of the two, I prefer the former.
My concern with using a function call is that it introduces/increases the potential for a file to say it uses a namespace that isn't yet defined. What happens then? Fatal? Autoload trigger? The code ends up un-packaged silently? (Please not the last one.)
I don't feel like "it's Composer's problem" is a good answer here. Making the package name be a class name at least makes autoloading a natural and well understood way to handle the lookup. There may be other benefits to using a class/methods to define a package, or possibly even downsides; I'm not sure there. More research needed. Same for avoiding package name collisions; "it's FIG's problem" may be an answer, but it seems like a poor one.
In practice I'd expect package definitions to be the obvious example of the preloader, but there will always be cases where the preloader is not available or cannot be used so we need to consider the performance impact of registering packages in every request.
Has anyone done in-depth research into how other languages handle packages, and what advantages packages would have over just our existing nested namespaces? I feel like there's ample prior art here that we should not ignore.
--Larry Garfield
I don't think declaring the package in each file is necessarily bad. Every language I've worked in either has you declare a package explicitly or implies it off of the file system and you don't get any say in the matter. Of the two, I prefer the former.
I concur with this, I would much rather specify a reference to external
metadata once-per-file than have it controlled by invisible external state.
If I send an individual file to a co-worker, IMO it should be
immediately obvious at the top of that file that it belongs to <x>
package and may depend on that package definition to control its
behaviour (especially if it gets loaded up with declares or editions).
I'll simply be replacing my ubiquitous strict-types declare with
whatever was used to reference this package.
Mark Randall
Hi Larry,
pon., 12 sie 2019 o 15:45 Larry Garfield larry@garfieldtech.com
napisał(a):
Has anyone done in-depth research into how other languages handle
packages, and what advantages packages would have over just our existing
nested namespaces? I feel like there's ample prior art here that we should
not ignore.
I did some writings on that
https://brzuchal.com/posts/packages-in-programming-languages/ was a little
hurry
but tried my best to grasp key aspects of package / module concept in other
languages.
--
regards / pozdrawiam,
Michał Brzuchalski
about.me/brzuchal
brzuchalski.com
Hi Nicolas,
pon., 12 sie 2019 o 10:17 Nicolas Grekas nicolas.grekas+php@gmail.com
napisał(a):
Le lun. 11 déc. 2017 à 14:44, Nikita Popov nikita.ppv@gmail.com a écrit
:Some time ago I introduced the following proposal for namespace-scoped
declares:https://wiki.php.net/rfc/namespace_scoped_declares
The idea is to allow specifying declare directives for a whole library or
project using:namespace_declare('Vendor\Lib', ['strict_types' => 1]);
I've finally gotten around to implementing this proposal (
https://github.com/php/php-src/pull/2972) and would like to move forward
with it.The reason why I'm picking it up again is some feedback I received for
the
explicit call-time send-by-ref proposal. The main objection seems to be
that the feature has limited usefulness if it's optional rather than
required, because you still can't be sure that something is a by-value
pass, just because no & is present. At the same time, we can't make this
required anytime soon due to the large BC impact.Namespace-scoped declares are perfectly suited to resolve this problem.
We
can introduce a require_explicit_send_by_ref declare directive to make
the
call-site annotation required, and libraries/projects can easily opt-in
to
it using namespace_declare(). There would be no BC impact, while at the
same time projects could benefit from the additional clarity and
performance improvements immediately.I've read discussions about the notion of a "package" and the way we should
define its boundaries.
What about the following?Individual files could declare their package using this style:
<?php declare(package=MyVendor\MyPackage);That would be enough to group a set of files together and make them share
eg some private classes, some optional PHP behaviors, etc.
Why suggesting use of declare for that?
Wouldn't a new "package" keyword be more appropriate for that?
For eg.:
<?php
package MyVendor\MyLib;
I was also thinking about it to be a part of FQCN cause PHP would figure
out package name from
namespaced symbol names.
Was even thinking about writing generic RFC for packages we could discuss
on and redirect discussion
into package related topic.
The right side "MyVendor\MyPackage" would also be a FQCN that PHP would
autoload as a regular class. The corresponding class would then be the
place where ppl would declare the engine behavior they want for their
package (strict types, etc). To enforce this, the engine could require that
the "MyPackage" class implements some interface/extend some base abstract
class.Of course, one could hijack a package and declare an unrelated file as part
of it, but I don't think that's an issue: the situation is the same as for
namespaces, where one can hijack a third party vendor namespace. In
practice, it proved not being an issue, and the original author's intent is
clear: "this is my namespace/package, if you mess with it, fine, but you're
on your own".Nicolas
--
regards / pozdrawiam,
Michał Brzuchalski
about.me/brzuchal
brzuchalski.com
Individual files could declare their package using this style:
<?php declare(package=MyVendor\MyPackage);That would be enough to group a set of files together and make them share
eg some private classes, some optional PHP behaviors, etc.The right side "MyVendor\MyPackage" would also be a FQCN that PHP would
autoload as a regular class. The corresponding class would then be the
place where ppl would declare the engine behavior they want for their
package (strict types, etc). To enforce this, the engine could require that
the "MyPackage" class implements some interface/extend some base abstract
class.
I really like this approach. It allows a package definition file to
exist, without either the language or the header of each file having to
define its location.
Importantly, although it would trigger the autoloader if not yet
defined, the package could be defined in advance, for instance as part
of a preload directive. It could even be possible to define multiple
packages in one file, or define them dynamically, using all the existing
features of the language like require and eval.
On a bikeshedding note, I've never liked the way declare syntax looks,
so would prefer a new keyword, but the symmetry of replacing <?php
declare(strict_types=1); with <?php
declare(package=Something\Defining\StrictOptions); is admittedly quite
appealing.
Regards,
--
Rowan Collins
[IMSoP]
I really like this approach. It allows a package definition file to
exist, without either the language or the header of each file having to
define its location.
File: /lib/company/project1/a/b/MyClass.php
<?php
declare_import(company[:label]);
namespace company/project1/a/b;
...
File: /lib/company/__nsmeta.php
<?php
namespace company;
namespace_declare [:label] {
strict_types=1;
strict_operators=1;
upgrade_errors_to_exceptions=E_ALL;
}
final class __nsmeta {
/* does nothing except be findable by the autoloader /
/ and defaults to private constructor so it can't be used */
}
...
Caveat would be for situations that do not use an autoloader, the
__nsmeta.php would need to be loaded first, this is something that
PHP7.4 autoloaders would need to take into consideration.
Mark Randall