Re: [RFC idea introduce] The issue where the __callStatic magic method is not called when statically calling a public method.
| From: | 하늘아부지 | Date: | Thu, 28 Mar 2024 12:02:38 +0000 |
| Subject: | Re: [RFC idea introduce] The issue where the __callStatic magic method is not called when statically calling a public method. | ||
| References: | 1 2 3 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-122788@lists.php.net to get a copy of this message | ||
2024년 3월 28일 (목) 오후 6:33, Stéphane Hulard <s.hulard@chstudio.fr>님이 작성:
> Le jeudi 28 mars 2024 à 10:40, Claude Pache <claude.pache@gmail.com> a
> écrit :
>
> >
>
> >
>
> > > Le 28 mars 2024 à 03:29, 하늘아부지 <daddyofsky@gmail.com> a écrit :
> > >
>
> > >
>
> > > Hi.
> > >
>
> > > I would like to register an RFC on the following issue.
> > > https://github.com/php/php-src/issues/13813
> > >
>
> > > To summarize briefly, users expect that the
> > >
__callStatic magic
> method will be called in all cases when a method is not static while using
> the __callStatic. However, in reality, if the method is public,
> the
> __callStatic magic method is not called, and an error still
> occurs.
> > >
>
> > > I would like to hear your opinions.
> > > I also hope someone can help with the RFC registration.
> > >
>
> > >
>
> > > --------------------------------------------------------
> > >
>
> > > ```php
> > > <?php
> > > class MyClass
> > > {
> > > public static function __callStatic($method, $args)
> > > {
> > > echo $method . "\n";
> > > }
> > >
>
> > > private function privateMethod() {}
> > > protected function protectedMethod() {}
> > > public function publicMethod() {}
> > > }
> > >
>
> > > MyClass::privateMethod();
> > > MyClass::protectedMethod();
> > > MyClass::publicMethod();
> > > ```
> > >
>
> > > Resulted in this output:
> > > ```
> > > privateMethod
> > > protectedMethod
> > > Fatal error: Uncaught Error: Non-static method MyClass::publicMethod()
> cannot be called statically in ...
> > > ```
> > >
>
> > > But I expected this output instead:
> > > ```
> > > privateMethod
> > > protectedMethod
> > > publicMethod
> > > ```
> > >
>
> > >
>
> >
>
> >
>
> > Hi,
> > One of the issue is that it is not possible to determine statically that
> a certain call is static or not. It is possible to determine it at runtime;
> but you must be careful to articulate clearly the rules. Although it is
> absolutely possible to have logical rules, I fear that they couldn’t be
> sufficiently simple in order to avoid confusion.
> >
>
> > In the following real-world (but hopefully rare) case (it is taken from
> my own codebase), I am calling a method of a grandparent class. It is *not*
> a static method:
> >
>
> > ```php
> >
>
> > foo = new class(/* ... */) extends Bar {
> >
>
> > // ...
> >
>
> > function Header() {
> > $grandparent_class = get_parent_class(parent::class);
> > $grandparent_class::Header();
> > // ... rest of code
> > }
> >
>
> > // ...
> > };
> > ```
> >
>
> > In the following more general case, I might intend to call to a static
> method. However, as of today, a call to a non-static method will occur if
> A has a non-static accessible method
> qux() *and* $this is an
> instance of A:
> >
>
> > ```php
> > class Foo {
> > function baz() {
> > A::qux();
> > }
> > }
> > ```
> >
>
> > (In older versions of PHP, a non-static call would occur even when
> $this is not an instance of A.
> Hopefully, this is no longer the case
> since PHP 8.)
> >
>
> >
>
> > —Claude
>
> Hello !
>
> In Laravel the static versus non static context is handled inside the
> different calls. So a static call on a non static method will be forwarded
> to a non static instance to be handled properly.
> I don't see any advantages to call __callStatic on any
> method call since
> the difference with __call is clear. Also, as Claude said,
> determining
> that the call is static or not is not easy.
>
> Also, building Singleton is possible using the current PHP behavior. An
> example :
>
> ```php
> <?php
>
> class User
> {
> public function __callStatic($name, $arguments)
> {
> return (new static)->$name(...$arguments);
> }
>
> public static function __call($name, $arguments)
> {
> // Here handle the call the $name method.
> echo $name;
> }
> }
>
> $user = User::find(1);
> //Will output
> // find
> ```
>
> That's the way it's done in Laravel. Also note that the find method
> doesn't exists in the User object. That's why it works, the method is truly
> "magic".
> If the method is defined as non static, it'll break with the error given.
>
> Stéphane
>
Hi.
I tested what Claude pointed out.
https://3v4l.org/qb6HH
From the test results and comments by iluuu1994 on GitHub ((
https://github.com/php/php-src/issues/13813#issuecomment-2021625413),
it
seems that visibility is checked first, followed by whether it's static or
not. I wonder if swapping these checks might solve the issue, but it seems
like this part will have to be left to the experts.
I understand what Stéphane pointed out. The part I'm interested in is
whether it's possible to use singletons easily without separating the
class. __call alone cannot solve this part.
For example, in Laravel, methods defined in the DB class can be called
through __callStatic in the Model class, but methods defined in the Model
class or classes inheriting from the Model class cannot be called using ::.
Therefore, scope-related methods must be implemented using a scope prefix.
You're using scopeKeyword methods like User::keyword. I think this awkward
usage and the grotesque form that arose because __callStatic is not called
in the case of all public methods.
daddyofsky