Re: RFC Proposal : Allows calling non-static public methods through the __callStatic magic method instead of throwing an error.
| From: | Claude Pache | Date: | Sat, 17 Feb 2024 21:26:44 +0000 |
| Subject: | Re: RFC Proposal : Allows calling non-static public methods through the __callStatic magic method instead of throwing an error. | ||
| References: | 1 2 | Groups: | php.internals |
| Request: | Send a blank email to internals+get-122416@lists.php.net to get a copy of this message | ||
> Le 17 févr. 2024 à 16:51, Larry Garfield <larry@garfieldtech.com> a écrit :
>
> On Fri, Feb 16, 2024, at 7:56 PM, 하늘아부지 wrote:
>> Hi.
>> I'd like to propose an RFC, but I don't have the authority.
>> Below is my suggestion.
>> If you think this makes sense, please write an RFC for me.
>> Sincerely.
>>
>> ----------------------------------------------------------
>>
>> ===== Introduction =====
>> Allows calling non-static public methods through the __callStatic magic
>> method instead of throwing an error.
>>
>> ===== Proposal =====
>>
>> From a conceptual perspective:
>> It goes without saying that calling a non-static method statically will
>> result in an error.
>> However, a confusing situation occurred when the __callStatic magic
>> method exists.
>> Non-public methods can be called, but public methods cannot.
>> This is the opposite of the method visibility policy.
>>
>> From a practical point of view:
>> If you can call Non-static public methods through the __callStatic
>> magic method, you can write code like Laravel ORM more simply and tidy.
>>
>> <code>
>> User::foo()->bar();
>> </code>
>>
>> ==== Before ====
>>
>> <code>
>> class Foo
>> {
>> protected static ?Foo $instance = null;
>>
>> public static function __callStatic($method, $args)
>> {
>> $instance = self::$instance ?? self::$instance = new static();
>> return $instance->__call($method, $args);
>> }
>>
>> public function __call($method, $args)
>> {
>> if (method_exists($this, $method)) {
>> return $instance->$method(...$args);
>> }
>>
>> return $this;
>> }
>>
>> protected function bar()
>> {
>> echo __METHOD__ . '<br />';
>>
>> return $this;
>> }
>>
>> protected function baz()
>> {
>> echo __METHOD__ . '<br />';
>>
>> return $this;
>> }
>> }
>>
>> Foo::bar()->baz();
>> (new Foo())->bar()->baz();
>> </code>
>>
>> There is no error, but the concept of method visibility is broken.
>> All Non-public methods can be called at instance scope.
>>
>> ==== After ====
>>
>> <code>
>> class Foo
>> {
>> protected static ?Foo $instance = null;
>>
>> public static function __callStatic($method, $args)
>> {
>> $instance = self::$instance ?? self::$instance = new static();
>>
>> if (method_exists($instance, $method)) {
>> return $instance->$method(...$args);
>> }
>>
>> return $instance;
>> }
>>
>> public function bar()
>> {
>> echo __METHOD__ . '<br />';
>>
>> return $this;
>> }
>>
>> public function baz()
>> {
>> echo __METHOD__ . '<br />';
>>
>> return $this;
>> }
>> }
>>
>> Foo::bar()->baz();
>> (new Foo())->bar()->baz();
>> </code>
>>
>> This is more tidy.
>> Only public methods are callable at instance scope.
>
> That calling bar() works at all in this example is rather accidental. The whole point of a
> non-static method is that it has an implicit required $this argument to it. Without a required
> argument, a method cannot be called, because it is supposed to fail.
>
> In fact, even your "before" example fails:
> https://3v4l.org/moH0s
It does work after having corrected the obvious bug in the
bar() method.
>
> I don't think what you describe is even possible, nor would it be a good idea.
Why wouldn’t it possible? Couldn’t the engine invoke __callStatic() instead of complaining that
the targeted method is not static? (I don’t have opinion on whether it is a good idea, though)
—Claude