Hi internals,

I would like to present my idea for namespaces refactoring and provide an
RFC for them.

Currently in PHP namespaces are implemented as a prefix of class or
function name. Using ReflectionClass or ReflectionFunction we can retrieve
class/function name and its namespace-name. In both situations it's
implemented as substring operation on class/function name:

ReflectionClass::getNamespaceName():
https://github.com/php/php-src/blob/master/ext/reflection/php_reflection.c#L5283
ReflectionFunction::getNamespaceName():
https://github.com/php/php-src/blob/master/ext/reflection/php_reflection.c#L3427

In both we can see the result of method is part of name.

IMHO those namespaces should be implemented as a struct like zend_namespace
struct with flags and name and should not be a part of class/function name.
Such change could increase performance on those Reflection* methods but not
only. I can see a good usage of such struct in implementing new features
like class/function visibility modifiers like: private, protected,
package-private or internal.

Some time ago there was discussion about final-properties I have started
https://marc.info/?t=145979255800003&r=1&w=2
In this discussion there was also talk about private class and internal
methods http://marc.info/?l=php-internals&m=146005798902985&w=2 as we can
see in PR https://github.com/php/php-src/pull/947#discussion_r21542750
which is little outdated there is implementation of class modifiers, and
there is exactly the same thing I was using in my package-private
implementation which uses string subctring comparison as we can see here in
ZEND_API int zend_is_same_namespace(const char *fc, const char *sc)
https://github.com/php/php-src/pull/947/files#diff-5459151fc119e0faf6f26162999c0cfdR2411

IMHO those hack's are result of badly implemented namespaces and leaving
them as they are won't bring new features highly optimized against
execution performance, because of string comparison.
Reimplementing namespaces as a struct could bring optimization level breat
boost as it can simply comapre pointer to zend_namespace struct.

An advantage of struct coult bring us new features like internal namespaces
in near future simply by flags field in zend_namespace struct - in feature
there could be some cleaning of build in classes and functions and move
into internal system namespace eg. \PHP\DateTime or whatever - not
important right now.

Another adwantage is comparing namespaces in class/function range modifiers
like private,protected,package-private or whatever.

There could be even some kind of extension flag for namespace providing
protection of namespace used in some extension awoiding to missusage and
providing some extension-private class/function implementations which could
be protected and the user would get an error while implementing, extending
- private classes from extension or smth like that.

I can see also some unconsistencies in class/function usage in PHP we can
use A/B::class to retrieve whole-class name with namespace, there could be
also some magic const like A/B::ns and it won't need to substring class
name, maybe in a future ther would be need to provide such syntax for
functions? A/c::ns where A/c is function, right now there is only way to
pass function name into ReflectionFunction as a string, classes have
::class magic const and it's easy to refactor such code, eg. change
namespace name which could lead to errors in IDE where functions are in
namespaces! Because searching for whole function name with namespace can
exists in code only as a string.

For eg. code like that:

<?php
namespace A {
    class B {}
    function c() {}
}
namespace {
    $cr = new ReflectionClass(A\B::class);
    var_dump($cr->getName(), $cr->getNamespaceName());
    $fr = new ReflectionFunction('A\c');
    var_dump($fr->getName(), $fr->getNamespaceName());
}

Will execute string substringing for class/function getNamespaceName()
reflection method which is simply SLOW! Such information isn't even cached!


Implementing such struct as zend_namespace could bring namespaces registry
at run-time. Such namespaces could have wheir parents as pointers to other
structs like in tree so they could optimize memory usage for eg. having
1000 classes in Test namespace preserves right now 1000 zend_string's with
class name and 1000 * 4 chars("Test") in quite longer namespace names those
numbers could be significant! The same is with function names.

I now it's not an easy task because there are lot of source code lines
which use zend_class->name and same for function pointers.

Nowadays probably none of extension uses namespaces so it's not a real
problem right now to provide such change.


Thanks for reading,
regards,
--
Michał Brzuchalski

Reply via email to