Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:122788 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by qa.php.net (Postfix) with ESMTPS id 9EF061AD8EA for ; Thu, 28 Mar 2024 12:02:59 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1711627404; bh=vnCciFqUAc1BJdiWWbZpyaTKhhdrzeaQX76Z0PKhmGc=; h=References:In-Reply-To:From:Date:Subject:To:From; b=GpxWlSMKZjg5lsMNWNuPXxwfpFXpl1FnlNjRrj4fOHL4QzGKq/Xx58JhOVdZwwVdR uE5clF4+ul6FetOmpgXNNDp2wwTkmNhA7FHk+Thm/Brv5YsZCT/V9AXRDBgb3q6oZx xZNetjYXpobHylCal2Uvsu/DPiORLfpF6J394ZqFpAk1UvSlDaBSK/aAPnnfnbwApY qMg2D/rgUJA58l6kHtUM9xiswRkiDoKnqYN0d6F+epMiEAdGBshQAqEc3R/wU6B3Ko m8WbhFSi65RI+7sJkFTrjTU4JdmU5ecXvm4lNdSaa33C3spVWPsu7+2GzHsD+9wzFj T2ITr5/DLIqxg== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id A3DCD180075 for ; Thu, 28 Mar 2024 12:03:20 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.0 (2022-12-13) on php-smtp4.php.net X-Spam-Level: ** X-Spam-Status: No, score=2.1 required=5.0 tests=BAYES_50,BODY_8BITS, DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,DMARC_PASS, FREEMAIL_FROM,HTML_MESSAGE,RCVD_IN_MSPIKE_H2,SPF_HELO_NONE,SPF_PASS, T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=4.0.0 X-Spam-Virus: No X-Envelope-From: Received: from mail-yw1-f181.google.com (mail-yw1-f181.google.com [209.85.128.181]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Thu, 28 Mar 2024 12:03:15 +0000 (UTC) Received: by mail-yw1-f181.google.com with SMTP id 00721157ae682-611248b4805so8924427b3.0 for ; Thu, 28 Mar 2024 05:02:50 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1711627369; x=1712232169; darn=lists.php.net; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :from:to:cc:subject:date:message-id:reply-to; bh=OMgBYwuXO7aQX29rNHcLczU4vD0I7C3l7TbMVdeV/F0=; b=T2tNl4mLdEtjQc+yyC6xpdzTvs3+4rH004lioBxh2SibugcbaS0uFN1Gmh7QxFtZpj cQ7DmZgVrakOe8Erqi5Xdqw8ysoy2hJVzJHaIW81V3tCQTnFgBty3AJXgbxWh1jzQL0w R51qC/5PvaEx4MzwkgeCuBE2St/Ov33l/XdYbjjRi1+uun/m1MZ+41emIN3syU5GkptX Rk5ywWvBBXT6MoGBmoVheJh9kghl9jV48yxqNy642C6Kj7NPAeFW/wBR4IKjlcZK/W7V t/GVJwRR7PkQQ5u0+31ekYy2uWSnxglCDEU3+qtt7IC0j8wvJutol3yxsCbf7FBD5sHl UDDw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1711627369; x=1712232169; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=OMgBYwuXO7aQX29rNHcLczU4vD0I7C3l7TbMVdeV/F0=; b=KKViSzIGkolk8oz3VuVXUWZ0KvPW97px5I3f+0VL8F3wXalLuPFHI5uUgTL//z2TAw Rb7+3awa4nBn2rq4MOfg91AYfvWXGrWY5FWelDmoMk9jIbi4HOAD7kzMPn7pRqV31zbM Za05tab9ANE4OMzy3ABgpYEG/BYay/fOLRmjz6GJRE69UYFV4QeKtj8qrgGgKfLattd6 lqAxoK3Mg0PC3gpxuMTOPq9cYZ2sk7DySVDhL1C2fSz091F4SI6CloTb+b+2ejDpsbtu hHfs3twG7d77qM/9Ijk8k2Dvq9K7KrG8b2gW5qZhVM6twTa4DGP2iFMGYBagmpkkIvP5 Cywg== X-Gm-Message-State: AOJu0YyOlN0l2zV2nJJTFzDM2ocKqMkycbJsY1UHeNziDTyM6tJR0/q/ NHdaV6GccTRLTgZzneA9x3RorTJzcNzd3of9iKJ9xnwqFNuJT8gHss9gCYkUMe9tzYh5GFBymR2 lJOC7zQn2JFmc+fOt4XZD1Br48MGwxzqQnAFwfZrO X-Google-Smtp-Source: AGHT+IHh529jzBIZqrknkUVjMGicI72czMuQbMQ6azB1fGyZ7ugwGW6hSBrv70uNa+yYX2NwAhbrDgmeqifo1NXA87g= X-Received: by 2002:a25:ae9c:0:b0:dda:a608:54bf with SMTP id b28-20020a25ae9c000000b00ddaa60854bfmr2858824ybj.56.1711627369224; Thu, 28 Mar 2024 05:02:49 -0700 (PDT) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net MIME-Version: 1.0 References: <3ECDC57B-9D22-4A0C-8E02-5720C90EF3BA@gmail.com> <8M2JTiUj7hdga1-ztER0KecraYT8pfwzSZPv0x64iikdUvBCK7n1rPzhacfBpkd8qQOiid7gSMpKeG9Zc4jtEIcl8U6LT05ou4X1RhDgPlM=@chstudio.fr> In-Reply-To: <8M2JTiUj7hdga1-ztER0KecraYT8pfwzSZPv0x64iikdUvBCK7n1rPzhacfBpkd8qQOiid7gSMpKeG9Zc4jtEIcl8U6LT05ou4X1RhDgPlM=@chstudio.fr> Date: Thu, 28 Mar 2024 20:02:38 +0800 Message-ID: Subject: Re: [PHP-DEV] [RFC idea introduce] The issue where the __callStatic magic method is not called when statically calling a public method. To: internals@lists.php.net Content-Type: multipart/alternative; boundary="00000000000054a5b30614b74d6a" From: daddyofsky@gmail.com (=?UTF-8?B?7ZWY64qY7JWE67aA7KeA?=) --00000000000054a5b30614b74d6a Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable 2024=EB=85=84 3=EC=9B=94 28=EC=9D=BC (=EB=AA=A9) =EC=98=A4=ED=9B=84 6:33, S= t=C3=A9phane Hulard =EB=8B=98=EC=9D=B4 =EC=9E=91=EC= =84=B1: > Le jeudi 28 mars 2024 =C3=A0 10:40, Claude Pache = a > =C3=A9crit : > > > > > > > > > > Le 28 mars 2024 =C3=A0 03:29, =ED=95=98=EB=8A=98=EC=95=84=EB=B6=80=EC= =A7=80 a =C3=A9crit : > > > > > > > > > > > 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 usin= g > 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 > > > > > 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 tha= t > a certain call is static or not. It is possible to determine it at runtim= e; > but you must be careful to articulate clearly the rules. Although it is > absolutely possible to have logical rules, I fear that they couldn=E2=80= =99t 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 *no= t* > a static method: > > > > > ```php > > > > > foo =3D new class(/* ... */) extends Bar { > > > > > // ... > > > > > function Header() { > > $grandparent_class =3D 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.) > > > > > > > > =E2=80=94Claude > > 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 forwarde= d > to a non static instance to be handled properly. > I don't see any advantages to call `__callStatic` on any method call sinc= e > 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 > > 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 =3D 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 tru= ly > "magic". > If the method is defined as non static, it'll break with the error given. > > St=C3=A9phane > 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=C3=A9phane 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 --00000000000054a5b30614b74d6a Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
2024=EB=85=84 3=EC=9B=94 28=EC=9D=BC (=EB=AA=A9) =EC=98=A4=ED=9B=84 = 6:33, St=C3=A9phane Hulard <s.hu= lard@chstudio.fr>=EB=8B=98=EC=9D=B4 =EC=9E=91=EC=84=B1:
Le jeudi 28 mars 2024 =C3=A0= 10:40, Claude Pache <claude.pache@gmail.com> a =C3=A9crit=C2=A0:

>

>

> > Le 28 mars 2024 =C3=A0 03:29, =ED=95=98=EB=8A=98=EC=95=84=EB=B6= =80=EC=A7=80 <= daddyofsky@gmail.com> a =C3=A9crit :
> >

> >

> > 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 `__ca= llStatic` 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::publicMet= hod() 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 th= at a certain call is static or not. It is possible to determine it at runti= me; but you must be careful to articulate clearly the rules. Although it is= absolutely possible to have logical rules, I fear that they couldn=E2=80= =99t be sufficiently simple in order to avoid confusion.
>

> In the following real-world (but hopefully rare) case (it is taken fro= m my own codebase), I am calling a method of a grandparent class. It is *no= t* a static method:
>

> ```php
>

> foo =3D new class(/* ... */) extends Bar {
>

> =C2=A0 =C2=A0 // ...
>

> =C2=A0 =C2=A0 function Header() {
> =C2=A0 =C2=A0 =C2=A0 =C2=A0 $grandparent_class =3D get_parent_class(pa= rent::class);
> =C2=A0 =C2=A0 =C2=A0 =C2=A0 $grandparent_class::Header();
> =C2=A0 =C2=A0 =C2=A0 =C2=A0// ... rest of code
> =C2=A0 =C2=A0 }
>

> =C2=A0 =C2=A0// ...
> };
> ```
>

> 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 = =C2=A0`A` has a non-static accessible method `qux()` *and* `$this` is an in= stance of `A`:
>

> ```php
> class Foo {
> =C2=A0 =C2=A0 function baz() {
> =C2=A0 =C2=A0 =C2=A0 =C2=A0 A::qux();
> =C2=A0 =C2=A0 }
> }
> ```
>

> (In older versions of PHP, a non-static call would occur even when `$t= his` is not an instance of `A`. Hopefully, this is no longer the case since= PHP 8.)
>

>

> =E2=80=94Claude

Hello !

In Laravel the static versus non static context is handled inside the diffe= rent 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 si= nce the difference with `__call` is clear. Also, as Claude said, determinin= g that the call is static or not is not easy.

Also, building Singleton is possible using the current PHP behavior. An exa= mple :

```php
<?php

class User
{
=C2=A0 =C2=A0 public function __callStatic($name, $arguments)
=C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 return (new static)->$name(...$arguments); =C2=A0 =C2=A0 }

=C2=A0 =C2=A0 public static function __call($name, $arguments)
=C2=A0 =C2=A0 {
=C2=A0 =C2=A0 =C2=A0 =C2=A0 // Here handle the call the $name method.
=C2=A0 =C2=A0 =C2=A0 =C2=A0 echo $name;
=C2=A0 =C2=A0 }
}

$user =3D User::find(1);
//Will output
//=C2=A0 =C2=A0find
```

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 give= n.

St=C3=A9phane


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-20= 21625413), it seems that visibility is checked first, followed by whether it's=20 static or not. I wonder if swapping these checks might solve the issue,=20 but it seems like this part will have to be left to the experts.

I understand what St=C3=A9phane pointed out. The part I'm interested in = is=20 whether it's possible to use singletons easily without separating the= =20 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 clas= s or classes inheriting from the Model class cannot be called using := :. Therefore, scope-related methods must be implemented using a scop= e prefix. You're using scopeKeyword methods like Use= r::keyword. I think this awkward usage and the grotesque form that a= rose because __callStatic is not called in the case of all pub= lic methods.

daddyofsky

=C2=A0
--00000000000054a5b30614b74d6a--