Re: [RFC] class_name:namespace

php.internals

Manuel Canga

5 years ago
-- Manuel Canga Zend Certified PHP Engineer Websites: https://manuelcanga.dev | https://trasweb.net Linkedin: https://es.linkedin.com/in/manuelcanga ---- En jue, 25 feb 2021 23:12:23 +0100 David Gebler <davidgebler@gmail.com> escribió ---- > You can achieve what you're trying to do already with a combination of > get_class() on a namespaced class and a simple regex (or other method of > processing a string to your liking): > > $foo = "My\\Namespace\\Name\\Class"; > var_dump(preg_match('/^(.*)\\\([^\\\]*)$/m',$foo,$matches),$matches); > > array(3) { > [0] => > string(23) "My\Namespace\Name\Class" > [1] => > string(17) "My\Namespace\Name" > [2] => > string(5) "Class" > } > > Regards > David Gebler > Hi, David. ::namespace notation would be more semantic and faster. Other example: In WordPress, classes use class-{{class-name}}.php notation for file of classes[1]. Example: class-wp-error.php An autoloader for WordPress could be: ``` <?php function autoload($fullClassName) { $filePath = str_replace('\\', '//', $fullClassName::namespace ); $className = ltrim(strrchr($fullClassName, '\\'), '\\'); $className = strtolower( str_replace('_', '-', $className ) ); require '{$filePath}/class-{$className}.php"; } spl_autoload_register('autoload'); ``` [1]: https://make.wordpress.org/core/handbook/best-practices/coding-standards/php/#naming-conventions -- Manuel Canga Zend Certified PHP Engineer Websites: https://manuelcanga.dev | https://trasweb.net Linkedin: https://es.linkedin.com/in/manuelcanga

Manuel Canga

5 years ago
Hello, another example with "factories method"[1]: ```php use MyProject\Framework; abstract class AbstractController { private const HELPER_PATH = static::namespace.'/Helpers'; private const SERVICE_PATH = static::namespace.'/Services'; public function instanceHelper( string $helperClass ) { $helperClassName = self::HELPER_PATH."/{$helperClass}"; return new $helperClassName(); } public function instanceService( string $serviceClass ) { $serviceClassName = self::SERVICE_PATH."/{$serviceClass}"; return new $serviceClassName(); } } use MyProject\MyModule; class Controller { public function __invoke() { //...... $date = $this->instanceHelper('Date'); //... } } ``` [1]: https://en.wikipedia.org/wiki/Factory_method_pattern Regards
-- Manuel Canga Zend Certified PHP Engineer Websites: https://manuelcanga.dev | https://trasweb.net Linkedin: https://es.linkedin.com/in/manuelcanga

Manuel Canga

5 years ago
I'm Sorry, I feel a little nervous by writing here again after long time. Replace '/' by '\' and PATH( HELPER_PATH | SERVICE_PATH ) by NAMESPACE( HELPER_NAMESPACE | SERVICE_NAMESPACE ). Sorry ---- En vie, 26 feb 2021 09:16:18 +0100 Manuel Canga <php@manuelcanga.dev> escribió ----

Glash Gnome

5 years ago
Hola Manuel, "Don't you think the same ?" I was thinking of something more generi, maybe : ``` namespace Foo\Bar; class A { static function getNamespace() { static $ns = __NAMESPACE__;// https://wiki.php.net/rfc/static_variable_inheritance return $ns; } } namespace My\Baz; class B extends \Foo\Bar\A { } echo \Foo\Bar\A::getNamespace(), PHP_EOL;// Foo\Bar echo \My\Baz\B::getNamespace(), PHP_EOL;// Foo\Bar Ho no ! ``` Unfortunately it doesn't work ... Best regards, Serge Le ven. 26 févr. 2021 à 09:26, Manuel Canga <php@manuelcanga.dev> a écrit :

Manuel Canga

5 years ago
---- En vie, 26 feb 2021 11:08:33 +0100 Glash Gnome <glash.gnome@gmail.com> escribió ----
> Hola Manuel, > "Don't you think the same ?" > I was thinking of something more generi, maybe : > ``` > namespace Foo\Bar; > > class A { > static function getNamespace() { > static $ns = __NAMESPACE__;// https://wiki.php.net/rfc/static_variable_inheritance > return $ns; > } > } > > namespace My\Baz; > class B extends \Foo\Bar\A { } > > echo \Foo\Bar\A::getNamespace(), PHP_EOL;// Foo\Bar > echo \My\Baz\B::getNamespace(), PHP_EOL;// Foo\Bar Ho no !``` > Unfortunately it doesn't work ... > > Best regards,Serge >
Hola, Glash, I sometimes use: class Foo { const NAMESPACE = __NAMESPACE__; } Foo::NAMESPACE; However, this doesn't work: class Bar extends Foo { } Bar::NAMESPACE; // == Foo::NAMESPACE Regards
-- Manuel Canga Zend Certified PHP Engineer Websites: https://manuelcanga.dev | https://trasweb.net Linkedin: https://es.linkedin.com/in/manuelcanga

Claude Pache

5 years ago
> Le 26 févr. 2021 à 09:16, Manuel Canga <php@manuelcanga.dev> a écrit : > > Hello, another example with "factories method"[1]: > > ```php > use MyProject\Framework; > > abstract class AbstractController { > private const HELPER_PATH = static::namespace.'/Helpers'; > private const SERVICE_PATH = static::namespace.'/Services'; > > public function instanceHelper( string $helperClass ) { > $helperClassName = self::HELPER_PATH."/{$helperClass}"; > > return new $helperClassName(); > } > > public function instanceService( string $serviceClass ) { > $serviceClassName = self::SERVICE_PATH."/{$serviceClass}"; > > return new $serviceClassName(); > } > } > > use MyProject\MyModule; > > class Controller { > public function __invoke() { > //...... > $date = $this->instanceHelper('Date'); > //... > } > > } > ``` > > [1]: https://en.wikipedia.org/wiki/Factory_method_pattern > > Regards > -- > Manuel Canga > > Zend Certified PHP Engineer > Websites: https://manuelcanga.dev | https://trasweb.net > Linkedin: https://es.linkedin.com/in/manuelcanga > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php
Hi, Note that (typos aside) this example cannot work as-is, because `static::namespace` (like `static::class`) cannot be resolved at compile-time, and therefore cannot be assigned to a constant. More generally, in the various examples you provided, the namespace is not resolved at compile-time: it is either static::namespace or $fullClassName::namespace where $fullClassName is provided by the autoloader. As such, instead of a ::namespace magic class constant, it might be more appropriate to have a helper function, say `get_namespace()`, which has the additional benefit to work not only on (fully qualified) class names, but also on function, constant and namespace names (in the case of namespace names, it would return the name of the parent namespace). —Claude

Manuel Canga

5 years ago
> > Hi, > > Note that (typos aside) this example cannot work as-is, because `static::namespace` (like `static::class`) cannot be resolved at compile-time, and therefore cannot be assigned to a constant. > > More generally, in the various examples you provided, the namespace is not resolved at compile-time: it is either static::namespace or $fullClassName::namespace where $fullClassName is provided by the autoloader. As such, instead of a ::namespace magic class constant, it might be more appropriate to have a helper function, say `get_namespace()`, which has the additional benefit to work not only on (fully qualified) class names, but also on function, constant and namespace names (in the case of namespace names, it would return the name of the parent namespace). > > —Claude > >
Hi, Claude, That's sound great. Something like dirname[1] but with namespaces. But...in that case, I also add a new function like basename but with namespaces. Example autoload for WordPress : ``` function autoload( $ful_class_name ) { $class_ path = str_replace('\\', '/', get_namespace( $ful_class_name ) ); $class_name = strtolower( get_base_namespace( $ful_class_name ) ); require "{$class_path}/class-{$class_name}.php"; }``` [1]: https://www.php.net/manual/es/function.dirname.php [2]: https://www.php.net/manual/es/function.basename.php Regards
-- Manuel Canga Zend Certified PHP Engineer Websites: https://manuelcanga.dev | https://trasweb.net Linkedin: https://es.linkedin.com/in/manuelcanga

Guilliam Xavier

5 years ago
On Fri, Feb 26, 2021 at 12:36 PM Manuel Canga <php@manuelcanga.dev> wrote:
> > > > Hi, > > > > Note that (typos aside) this example cannot work as-is, because > `static::namespace` (like `static::class`) cannot be resolved at > compile-time, and therefore cannot be assigned to a constant. > > > > More generally, in the various examples you provided, the namespace is > not resolved at compile-time: it is either static::namespace or > $fullClassName::namespace where $fullClassName is provided by the > autoloader. As such, instead of a ::namespace magic class constant, it > might be more appropriate to have a helper function, say `get_namespace()`, > which has the additional benefit to work not only on (fully qualified) > class names, but also on function, constant and namespace names (in the > case of namespace names, it would return the name of the parent namespace). > > > > —Claude > > > > > > Hi, Claude, > > That's sound great. Something like dirname[1] but with namespaces. > > But...in that case, I also add a new function like basename but with > namespaces. Example autoload for WordPress : > > ``` > function autoload( $ful_class_name ) { > > $class_ path = str_replace('\\', '/', get_namespace( $ful_class_name ) ); > $class_name = strtolower( get_base_namespace( $ful_class_name ) ); > > require "{$class_path}/class-{$class_name}.php"; > > }``` > > [1]: https://www.php.net/manual/es/function.dirname.php > [2]: https://www.php.net/manual/es/function.basename.php >
Hi, For that example (and most others), you're manipulating file paths anyway, and assume that the FQCN is at least one level deep (i.e. not top-level), so you may as well start with `$p = str_replace('\\', \DIRECTORY_SEPARATOR, $fqcn);` then use `dirname($p)` and/or `basename($p)`. Now for the (rarer) cases when you actually want the namespace name and/or the unqualified class name, I agree that the current state is not ideal. To my knowledge, you have the choice between "magic" string manipulation (various ways) and "semantic" reflection (e.g. `$r = new \ReflectionClass($fqcn);` -- which may try to autoload the class and throws if it doesn't actually exist -- then use `$r->getNamespaceName()` and/or `$r->getShortName()`). Like `str_contains()` was introduced as a "shorthand" for `false !== strpos()`, something like `get_namespace_name()` and/or `get_short_name()` (or other namings) might be worth considering. Regards,
-- Guilliam Xavier

Manuel Canga

5 years ago
---- En vie, 26 feb 2021 14:40:03 +0100 Guilliam Xavier <guilliam.xavier@gmail.com> escribió ----
> Hi, > > For that example (and most others), you're manipulating file paths anyway, > and assume that the FQCN is at least one level deep (i.e. not top-level), > so you may as well start with `$p = str_replace('\\', \DIRECTORY_SEPARATOR, > $fqcn);` then use `dirname($p)` and/or `basename($p)`. > > Now for the (rarer) cases when you actually want the namespace name and/or > the unqualified class name, I agree that the current state is not ideal. > To my knowledge, you have the choice between "magic" string manipulation > (various ways) and "semantic" reflection (e.g. `$r = new > \ReflectionClass($fqcn);` -- which may try to autoload the class and throws > if it doesn't actually exist -- then use `$r->getNamespaceName()` and/or > `$r->getShortName()`). > Like `str_contains()` was introduced as a "shorthand" for `false !== > strpos()`, something like `get_namespace_name()` and/or `get_short_name()` > (or other namings) might be worth considering. > > Regards, > > -- > Guilliam Xavier >
Hi, Guilliam, I think so. I don't need `dirname` function in order to extract path from a file name. However, `dirname` exists in order to simplify a "common" task in a semantic way. Why don't the same with namespaces ?. There is nothing specific in order to work with namespaces only they can be used. Regards
-- Manuel Canga Zend Certified PHP Engineer Websites: https://manuelcanga.dev | https://trasweb.net Linkedin: https://es.linkedin.com/in/manuelcanga

Michał Brzuchalski

5 years ago
Hi Manuel, pt., 26 lut 2021 o 09:17 Manuel Canga <php@manuelcanga.dev> napisał(a):
> Hello, another example with "factories method"[1]: > > ```php > use MyProject\Framework; > > abstract class AbstractController { > private const HELPER_PATH = static::namespace.'/Helpers'; > private const SERVICE_PATH = static::namespace.'/Services'; > > public function instanceHelper( string $helperClass ) { > $helperClassName = self::HELPER_PATH."/{$helperClass}"; > > return new $helperClassName(); > } > > public function instanceService( string $serviceClass ) { > $serviceClassName = self::SERVICE_PATH."/{$serviceClass}"; > > return new $serviceClassName(); > } > } > > use MyProject\MyModule; > > class Controller { > public function __invoke() { > //...... > $date = $this->instanceHelper('Date'); > //... > } > > } > ``` > > [1]: https://en.wikipedia.org/wiki/Factory_method_pattern
Personally, none of the above examples is convincing bc I'd implement them using a fixed class names map to avoid loading untrusted classes. Any kind of helper class is something I'd personally not use to avoid static coupling of code and hacks while writing unit tests over services that could be injected by IoC. Full class names (whether they're aliased or used in use clause) have more benefit over class name string operations as they're easy for any renaming which most of the IDE's these days can handle. IMO introducing namespace magic constant has relatively narrow use and I'd probably vote NO on this. Cheers, Michał Marcin Brzuchalski

Manuel Canga

5 years ago
---- En vie, 26 feb 2021 13:25:30 +0100 Michał Marcin Brzuchalski <michal.brzuchalski@gmail.com> escribió ----
> Personally, none of the above examples is convincing bc I'd implement them > using a fixed class names map to avoid loading untrusted classes. > Any kind of helper class is something I'd personally not use to avoid > static coupling of code and hacks while writing unit tests over > services that could be injected by IoC. > Full class names (whether they're aliased or used in use clause) have more > benefit over class name string operations as they're easy for any renaming > which most of the IDE's these days can handle. > IMO introducing namespace magic constant has relatively narrow use and I'd > probably vote NO on this. > > Cheers, > Michał Marcin Brzuchalski
I see... I agree with you, however one thing is as we would like PHP will be used and other is as it is used. - https://stackoverflow.com/questions/24798621/how-can-i-get-the-full-namespace-of-a-class-without-creating-an-instance-of-it - https://stackoverflow.com/questions/13932289/get-php-class-namespace-dynamically - https://stackoverflow.com/questions/43630010/php-how-can-get-the-namespace-of-class-method-parameter - https://stackoverflow.com/questions/28182783/get-namespace-of-an-object-using-an-abstract-class-or-trait/28182941 - ... It's like `eval`, it is dangerous, maybe it never should be used. However, sometimes is useful. do we avoid "dangerous" features ? or do we think people are professional( I don't know if this is used in English equal Spanish ) and they know using it when is needed ? I think that if something is common and normally useful, PHP should implement that. For example, `::namespace` or `get_namespace()` Regards
-- Manuel Canga Zend Certified PHP Engineer Websites: https://manuelcanga.dev | https://trasweb.net Linkedin: https://es.linkedin.com/in/manuelcanga