Re: [PHP-DEV] [RFC]

This is only part of a thread. view whole thread
  108531
February 13, 2020 07:57 rowan.collins@gmail.com (Rowan Tommins)
On 12 February 2020 23:12:34 GMT+00:00, Manuel Canga <manuelcanga@gmail.com> wrote:
>El mié., 12 feb. 2020 23:01, Rowan Tommins collins@gmail.com> >escribió: >In your example, you has the same options: > >> >1. Change import >2. Add namespace: > >['Acme\Global\I18N',\translate::function]
There is no collision between 'Foo::translate()' and 'translate()', so there is no reason to change the import. That's true of executing the functions, so it should remain be true of resolving them to strings.
>Explain: > >When you do: [ class, method ] or [ $object, method ]. Method has not >namespace, you write it without namespace( like global functions )
I think this is where we are thinking differently. A method name is not "like a global function", it's just a name; it doesn't belong in the same category. You might have any number of classes that use the same method name, but with completely different parameters and purpose, so "a method named foo" isn't a useful concept outside some specific class or interface. On the other hand, you can only have one function with a particular fully-qualified name, and the proposed feature is a way of referencing that.
>Other example: > >$class = \MyClass::class; >$method = \method::function; > >and... > >$class = '\MyClass'; >$method = 'method'; > >$obj = new $class(); >$obj->$method(); > >Both are the same, but first is more semantic.
This isn't semantic at all - it works only because \method::function happens to return the string you want, but so does \method::class; neither is actually labelling it as what it is, which is a method within class \MyClass. Importantly, it might not work at all, if ::function gives an error if the function doesn't exist. Regards, -- Rowan Tommins [IMSoP]
  108536
February 13, 2020 12:04 manuelcanga@gmail.com (Manuel Canga)
On Thu, 13 Feb 2020 at 08:58, Rowan Tommins collins@gmail.com> wrote:

> On 12 February 2020 23:12:34 GMT+00:00, Manuel Canga < > manuelcanga@gmail.com> wrote: > >El mié., 12 feb. 2020 23:01, Rowan Tommins collins@gmail.com> > >escribió: > >In your example, you has the same options: > > > >> > >1. Change import > >2. Add namespace: > > > >['Acme\Global\I18N',\translate::function] > > > There is no collision between 'Foo::translate()' and 'translate()', so > there is no reason to change the import. That's true of executing the > functions, so it should remain be true of resolving them to strings. > > There is collision with import which you added.
> > > >Explain: > > > >When you do: [ class, method ] or [ $object, method ]. Method has not > >namespace, you write it without namespace( like global functions ) > > > I think this is where we are thinking differently. A method name is not > "like a global function", it's just a name; it doesn't belong in the same > category. > > You might have any number of classes that use the same method name, but > with completely different parameters and purpose, so "a method named foo" > isn't a useful concept outside some specific class or interface. > > On the other hand, you can only have one function with a particular > fully-qualified name, and the proposed feature is a way of referencing that. > > Function as callable is different as regular function. Example:
http://sandbox.onlinephpfunctions.com/code/99408213d1ed740f60471646f16f9765d7efa93e namespace MyProject; function my_function() { //.... } my_function(); // it calls to \MyProject\my_function array_map('my_function', [] ); //* * Here, 'my_function' is only a string. Maybe a global function( without namespace ) or maybe a method or other case. With native array_map is a global function. However, you can have a function like this: function array_map( $method, $array) { \Collection::$method( $array ); } In both cases, you could do: array_map(\my_function::function, [] );
> > > >Other example: > > > >$class = \MyClass::class; > >$method = \method::function; > > > >and... > > > >$class = '\MyClass'; > >$method = 'method'; > > > >$obj = new $class(); > >$obj->$method(); > > > >Both are the same, but first is more semantic. > > > This isn't semantic at all - it works only because \method::function > happens to return the string you want, but so does \method::class; neither > is actually labelling it as what it is, which is a method within class > \MyClass. > > Importantly, it might not work at all, if ::function gives an error if > the function doesn't exist. > > ::function only would retrieve string, like as ::class, exists or not. In
fach, that code might not work at all due to class. What matter if Class does't exist ?. ::class doesn't produce error. Look: http://sandbox.onlinephpfunctions.com/code/0a8466a00974bc1ffc12b219569ced55753327bd If class doesn't exist, nothing happend. Thank, Rowan. You points of view are very interesting.
  108538
February 13, 2020 13:17 rowan.collins@gmail.com (Rowan Tommins)
On Thu, 13 Feb 2020 at 12:04, Manuel Canga <manuelcanga@gmail.com> wrote:

> > > On Thu, 13 Feb 2020 at 08:58, Rowan Tommins collins@gmail.com> > wrote: > >> On 12 February 2020 23:12:34 GMT+00:00, Manuel Canga < >> manuelcanga@gmail.com> wrote: >> >El mié., 12 feb. 2020 23:01, Rowan Tommins collins@gmail.com> >> >escribió: >> >In your example, you has the same options: >> > >> >> >> >1. Change import >> >2. Add namespace: >> > >> >['Acme\Global\I18N',\translate::function] >> >> >> There is no collision between 'Foo::translate()' and 'translate()', so >> there is no reason to change the import. That's true of executing the >> functions, so it should remain be true of resolving them to strings. >> >> There is collision with import which you added. >
There is no collision. This is perfectly valid PHP code: namespace Foo; use \explode; class Bomb { public static function explode() { return 'Bang! Bang!'; } } $bangs = explode(' ', Bomb::explode()); There is no ambiguity here, explode(...) refers precisely to the global function 'explode' which is unrelated to the class method 'Bomb::explode'. The same applies if I import the function from somewhere other than the global namespace: namespace Foo; use Acme\BetterArrayFunctions\explode; class Bomb { public static function explode() { return 'Bang! Bang!'; } } $bangs = explode(' ', Bomb::explode()); Again, there is no ambiguity, explode(...) refers precisely to the function 'Acme\BetterArrayFunctions\explode, which is unrelated to the class method 'Bomb::explode. "explode::function" should mean "if I run explode() here, what is the fully-qualified name of the function that would run?" If there's no ambiguity of which function would run, there's no ambiguity of what value ::function should return.
> * Here, 'my_function' is only a string. Maybe a global function( without > namespace ) or maybe a method or other case. With native array_map is a > global function. However, you can have a function like this: > > function array_map( $method, $array) { > \Collection::$method( $array ); > } > > In both cases, you could do: > > array_map(\my_function::function, [] ); >
In the second case, it would be incorrect to use \my_function::function, because you do not want the answer to the question "if I run \my_function() here, what is the fully-qualified name of the function that would run?" Annotating the argument that way wouldn't be useful for tools, either - e.g. an IDE like PHPStorm would see ::function and offer "jump to definition", but in this case it would jump to the definition of the global function my_function, which is actually irrelevant.
> > >> Importantly, it might not work at all, if ::function gives an error if >> the function doesn't exist. >> >> > ::function only would retrieve string, like as ::class, exists or not. In > fach, that code might not work at all due to class. What matter if Class > does't exist ?. ::class doesn't produce error. Look: > http://sandbox.onlinephpfunctions.com/code/0a8466a00974bc1ffc12b219569ced55753327bd >
As pointed out elsewhere, an implementation of ::function would need to be smarter than ::class, because unqualified function calls look first in the current namespace, then fall back to global scope. For example: namespace Foo; function explode() {} echo implode::function; // Should return 'implode', because that is what implode() would run echo explode::function; // Should return 'Foo\explode', because that is what explode() would run Regards, -- Rowan Tommins [IMSoP]