Re: [PHP-DEV] [RFC]

This is only part of a thread. view whole thread
  108521
February 12, 2020 21:47 manuelcanga@gmail.com (Manuel Canga)
El mié., 12 feb. 2020 22:36, Rowan Tommins collins@gmail.com>
escribió:

> On 11/02/2020 15:13, Manuel Canga wrote: > > One case which string can be useful but a callable would not be > acceptable is: > > > > array_map([I18N::class, translate::function] ); > > > I wouldn't expect that to work anyway, because the whole purpose of the > keyword would be to resolve "translate" as a function name, not a method > name, e.g. > > use Acme\Global\I18N; > use function Acme\Global\translate; > > var_dump([I18N::class, translate::function]); > > # array(0 => 'Acme\Global\I18N', 1 => 'Acme\Global\translate') > # not a valid callable > > var_dump([I18N::class, 'translate']); > > # array(0 => 'Acme\Global\I18N', 1 => 'translate'); > # this was what was intended > > > If you didn't want to quote the method, you'd need some other syntax > that took both class and method name, like: > > [I18N, translate]::callable > > Or as proposed elsewhere in the thread: > > $(I18N::translate) > > > Regards, >
Hi, You is importing function and you are using different. It is the same case like: namespace MyProject; use Vendor/Controller; class Controller extends Controller { }
>
  108522
February 12, 2020 22:01 rowan.collins@gmail.com (Rowan Tommins)
On 12/02/2020 21:47, Manuel Canga wrote:
> You is importing function and you are  using different. It is the same > case like: > > namespace MyProject; > > use Vendor/Controller; > > class Controller extends Controller { > }
In that example, you're defining two things of the same type with the same name, which would be an error; that's not what was happening in my example. In a call like Acme\Global\I18N::translate, or a callable like ['Acme\Global\I18N', 'translate'], the "translate" part never refers to a function in the current namespace, or indeed any namespace, only to a method of that particular class. But if you write ['Acme\Global\I18N', translate::function], there's no way for the engine to know that you wanted a method name rather than a function name, so it will try to resolve it in the current namespace and import list. That will either give an error, because there is no function called translate; or it will give you a fully-qualified name, which isn't what you wanted, you just wanted the string 'translate'. Regards, -- Rowan Tommins (né Collins) [IMSoP]
  108526
February 12, 2020 23:12 manuelcanga@gmail.com (Manuel Canga)
El mié., 12 feb. 2020 23:01, Rowan Tommins collins@gmail.com>
escribió:

> On 12/02/2020 21:47, Manuel Canga wrote: > > You is importing function and you are using different. It is the same > > case like: > > > > namespace MyProject; > > > > use Vendor/Controller; > > > > class Controller extends Controller { > > } > > > In that example, you're defining two things of the same type with the > same name, which would be an error; that's not what was happening in my > example. > > In a call like Acme\Global\I18N::translate, or a callable like > ['Acme\Global\I18N', 'translate'], the "translate" part never refers to > a function in the current namespace, or indeed any namespace, only to a > method of that particular class. > > But if you write ['Acme\Global\I18N', translate::function], there's no > way for the engine to know that you wanted a method name rather than a > function name, so it will try to resolve it in the current namespace and > import list. That will either give an error, because there is no > function called translate; or it will give you a fully-qualified name, > which isn't what you wanted, you just wanted the string 'translate' >
You're right about my example. This is good example: namespace MyProject; use Vendor\Controller; class MyController extends Controller { ...... } This is an error, if Controller has actually MyProyect namespace. Then, you have two options: 1. Change import 2. Add namespace to class Controller In your example, you has the same options:
> 1. Change import
2. Add namespace: ['Acme\Global\I18N',\translate::function] Explain: When you do: [ class, method ] or [ $object, method ]. Method has not namespace, you write it without namespace( like global functions ) then you do the same with ::function. This is [ class, \method::function ] or [ $object, \method::function ] Other example: $class = \MyClass::class; $method = \method::function; $obj = new $class(); $obj->$method(); and... $class = '\MyClass'; $method = 'method'; $obj = new $class(); $obj->$method(); Both are the same, but first is more semantic.
  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]