Hello.
I created a wiki for __callStatic related issues.
Please see:
https://wiki.php.net/rfc/complete_callstatc_magic
I look forward to your interest and advice.
Best Regards.
Daddyofsky
Le vendredi 29 mars 2024 à 03:39, 하늘아부지 daddyofsky@gmail.com a écrit :
Hello.
I created a wiki for __callStatic related issues.
Please see:
https://wiki.php.net/rfc/complete_callstatc_magic
I look forward to your interest and advice.
Best Regards.
Daddyofsky
Hello !
I took a look at your proposal and I think about important issues if we go this way.
A static method mustn't used the $this
variable because it simply doesn't exists in the static context. The examples you're adding in the RFC are fine but they always rely to a specific __callStatic
implementation that will use a new instance of the object to forward the call.
There are multiple cases where it'll be complicated to use it this way. Two of them I have in mind:
- What if the object needs important parameters in its constructor that aren't available in the static context ? Or those parameters need to be initialized outside of the
__callStatic
method? - What if the underlying non static method we are trying to invoke is using the
$this
variable?
In those two examples, I would prefer having a fatal error that explains that I'm not doing the call correctly (calling a non static method in the static context) to ensure it'll be easy to understand and fix.
The use cases you are describing here have been fixed in the user space by the Laravel team. It's a very specific way of working that's mostly specific to Laravel.
For sure it makes the code harder to read since you can't jump to a real method easily (because most of the methods are magic ones and are forwarded to underlying objects). I don't tell it's wrong but I'm not sure it's relevant to make the whole language simplify this process.
If there is a way to work correctly with those static vs non static calls and capture relevant errors to expose them to users, that's fine.
However, I think this is an important behavior change because it'll allow a new way to work with method that were forbidden before.
Regards
Stéphane
2024년 3월 29일 (금) 오후 5:43, Stéphane Hulard s.hulard@chstudio.fr님이 작성:
Le vendredi 29 mars 2024 à 03:39, 하늘아부지 daddyofsky@gmail.com a écrit :
Hello.
I created a wiki for __callStatic related issues.
Please see:
https://wiki.php.net/rfc/complete_callstatc_magicI look forward to your interest and advice.
Best Regards.
DaddyofskyHello !
I took a look at your proposal and I think about important issues if we go
this way.A static method mustn't used the
$this
variable because it simply
doesn't exists in the static context. The examples you're adding in the RFC
are fine but they always rely to a specific__callStatic
implementation
that will use a new instance of the object to forward the call.There are multiple cases where it'll be complicated to use it this way.
Two of them I have in mind:
- What if the object needs important parameters in its constructor that
aren't available in the static context ? Or those parameters need to be
initialized outside of the__callStatic
method?- What if the underlying non static method we are trying to invoke is
using the$this
variable?In those two examples, I would prefer having a fatal error that explains
that I'm not doing the call correctly (calling a non static method in the
static context) to ensure it'll be easy to understand and fix.The use cases you are describing here have been fixed in the user space by
the Laravel team. It's a very specific way of working that's mostly
specific to Laravel.For sure it makes the code harder to read since you can't jump to a real
method easily (because most of the methods are magic ones and are forwarded
to underlying objects). I don't tell it's wrong but I'm not sure it's
relevant to make the whole language simplify this process.If there is a way to work correctly with those static vs non static calls
and capture relevant errors to expose them to users, that's fine.However, I think this is an important behavior change because it'll allow
a new way to work with method that were forbidden before.Regards
Stéphane
Hello.
Thank you for your interest.
In fact, __callStatic
is often used for static-like singletons, and such
examples are likely to be the majority.
Regarding the two issues you pointed out, the first can be resolved by
adding an initialization method like init
. It's common to use a separate
initialization function when dealing with general class operations,
especially when there is a lot to initialize.
The second issue is actually the same problem that exists today. Since
__callStatic
is called in the case of static calls to private or
protected methods, the use of $this
is not exclusive to public methods.
In other words, the $this
issue applies the same way it does now.
Allowing public methods does not create a problem that didn't exist before.
If it had been the case that calling non-static methods statically always
resulted in an error, the issues you raised would have been significant.
However, private and protected methods can already be called without error.
Even if this RFC is not accepted, the points you mentioned still apply.
Regards
Daddyofsky
Hello.
I created a wiki for __callStatic related issues.
Please see:
https://wiki.php.net/rfc/complete_callstatc_magic
I look forward to your interest and advice.
I am firmly against this proposal.
I think my objection boils down to this line in the RFC:
Of course, calling non-static methods in a static-like manner can be confusing, but in modern PHP, it has already become common practice.
I would argue this statement is false. Calling non-static methods in a static-like manner is confusing, which is why in modern PHP one should never do that, and respect that static and non-static methods exist in a separate universe. Static methods are methods on a type. Non-static methods are methods on an instance. Those are not the same thing.[1]
It would be more accurate to say "calling non-static methods in a static-like manner is common in Laravel," where the badly-named "facades" system serves as a poorly designed, hard to debug, hard to test, archaic alternative to using dependency injection. While there may have once been an argument that DI was "too hard" for simple cases a decade ago or more (though even then I think it was a bade trade-off), the combination of auto-wiring DI Containers (which Laravel pioneered in PHP) and constructor promotion (introduced in PHP 8.0, 3.5 years ago.) completely eliminates those arguments. The level of effort to do actual DI today is trivially small, and the benefits over magic hidden globals are massive.
Laravel Facades are a relic of an older time best avoided, even in Laravel projects. (I am far from the only person to argue this; many even within Laravel's inner community make this argument.)
Adding features to the language that seemingly exist only to make that particular buggy hack easier to do is a step backwards, and I would argue harmful for the language. On the contrary, I would favor going the other direction: Calling a static method as though it were non-static currently works, and I would support making that an error, to further emphasize that static and non-static methods are not interchangeable.
[1] https://peakd.com/hive-168588/@crell/cutting-through-the-static
--Larry Garfield
2024년 3월 29일 (금) 오후 10:21, Larry Garfield larry@garfieldtech.com님이 작성:
Hello.
I created a wiki for __callStatic related issues.
Please see:
https://wiki.php.net/rfc/complete_callstatc_magic
I look forward to your interest and advice.I am firmly against this proposal.
I think my objection boils down to this line in the RFC:
Of course, calling non-static methods in a static-like manner can be
confusing, but in modern PHP, it has already become common practice.I would argue this statement is false. Calling non-static methods in a
static-like manner is confusing, which is why in modern PHP one should
never do that, and respect that static and non-static methods exist in a
separate universe. Static methods are methods on a type. Non-static
methods are methods on an instance. Those are not the same thing.[1]It would be more accurate to say "calling non-static methods in a
static-like manner is common in Laravel," where the badly-named "facades"
system serves as a poorly designed, hard to debug, hard to test, archaic
alternative to using dependency injection. While there may have once been
an argument that DI was "too hard" for simple cases a decade ago or more
(though even then I think it was a bade trade-off), the combination of
auto-wiring DI Containers (which Laravel pioneered in PHP) and constructor
promotion (introduced in PHP 8.0, 3.5 years ago.) completely eliminates
those arguments. The level of effort to do actual DI today is trivially
small, and the benefits over magic hidden globals are massive.Laravel Facades are a relic of an older time best avoided, even in Laravel
projects. (I am far from the only person to argue this; many even within
Laravel's inner community make this argument.)Adding features to the language that seemingly exist only to make that
particular buggy hack easier to do is a step backwards, and I would argue
harmful for the language. On the contrary, I would favor going the other
direction: Calling a static method as though it were non-static currently
works, and I would support making that an error, to further emphasize that
static and non-static methods are not interchangeable.[1] https://peakd.com/hive-168588/@crell/cutting-through-the-static
--Larry Garfield
Thank you for your feedback.
I agree that static and non-static should be distinct, which is a given.
There are a few points I'd like to make.
First, my proposed RFC is not about allowing non-static methods to be used
statically. Although all my examples use ::
, they internally operate on
an instance. Inside __callStatic
, an instance is created and used for
operations.
Second, as already possible through the __callStatic
method, non-static
methods can be called as if they were static (as mentioned, this does not
mean they operate statically). For protected and private methods, the
__callStatic
function is invoked even for non-static methods. This might
not be to everyone's liking, and to others, it might be a favorite feature.
It might operate differently from the initial intention when __callStatic
was introduced. However, I don't think this is necessarily a bad thing.
Isn't it developers who bring to life ingenious ideas that were unforeseen?
Third, as you can see from my examples, what I propose could be a solution
to the current issues. Since it does not work for public methods while it
does for protected and private ones, it has led to code becoming more
obscure and layered through facade-like patterns. It's like taking a longer
route because the road is blocked, or creating a dog door because the main
door is closed.
From the perspective of those who develop the PHP language itself, my
proposal might not be appealing. However, I believe from the user's
standpoint, my proposal could lead to more convenient and cleaner coding
practices. Didn't PHP start as a language meant to be user-friendly?
Regards
Daddyofsky
2024년 3월 29일 (금) 오후 10:21, Larry Garfield larry@garfieldtech.com님이 작성:
Hello.
I created a wiki for __callStatic related issues.
Please see:
https://wiki.php.net/rfc/complete_callstatc_magic
I look forward to your interest and advice.I am firmly against this proposal.
I think my objection boils down to this line in the RFC:
Of course, calling non-static methods in a static-like manner can be confusing, but in modern PHP, it has already become common practice.
I would argue this statement is false. Calling non-static methods in a static-like manner is confusing, which is why in modern PHP one should never do that, and respect that static and non-static methods exist in a separate universe. Static methods are methods on a type. Non-static methods are methods on an instance. Those are not the same thing.[1]
It would be more accurate to say "calling non-static methods in a static-like manner is common in Laravel," where the badly-named "facades" system serves as a poorly designed, hard to debug, hard to test, archaic alternative to using dependency injection. While there may have once been an argument that DI was "too hard" for simple cases a decade ago or more (though even then I think it was a bade trade-off), the combination of auto-wiring DI Containers (which Laravel pioneered in PHP) and constructor promotion (introduced in PHP 8.0, 3.5 years ago.) completely eliminates those arguments. The level of effort to do actual DI today is trivially small, and the benefits over magic hidden globals are massive.
Laravel Facades are a relic of an older time best avoided, even in Laravel projects. (I am far from the only person to argue this; many even within Laravel's inner community make this argument.)
Adding features to the language that seemingly exist only to make that particular buggy hack easier to do is a step backwards, and I would argue harmful for the language. On the contrary, I would favor going the other direction: Calling a static method as though it were non-static currently works, and I would support making that an error, to further emphasize that static and non-static methods are not interchangeable.
[1] https://peakd.com/hive-168588/@crell/cutting-through-the-static
--Larry Garfield
Thank you for your feedback.
I agree that static and non-static should be distinct, which is a given.There are a few points I'd like to make.
First, my proposed RFC is not about allowing non-static methods to be
used statically. Although all my examples use::
, they internally
operate on an instance. Inside__callStatic
, an instance is created
and used for operations.Second, as already possible through the
__callStatic
method,
non-static methods can be called as if they were static (as mentioned,
this does not mean they operate statically). For protected and private
methods, the__callStatic
function is invoked even for non-static
methods. This might not be to everyone's liking, and to others, it
might be a favorite feature. It might operate differently from the
initial intention when__callStatic
was introduced. However, I don't
think this is necessarily a bad thing. Isn't it developers who bring to
life ingenious ideas that were unforeseen?
Developers also bring to life horrible monstrosities that are an afront to all that is holy. I am a developer. It's what we do. :-) Especially when VC money is involved.
Not all "innovation" is good.
Third, as you can see from my examples, what I propose could be a
solution to the current issues. Since it does not work for public
methods while it does for protected and private ones, it has led to
code becoming more obscure and layered through facade-like patterns.
It's like taking a longer route because the road is blocked, or
creating a dog door because the main door is closed.
It simplifies a practice that should not be a practice in the first place. That's not a net-win.
From the perspective of those who develop the PHP language itself, my
proposal might not be appealing. However, I believe from the user's
standpoint, my proposal could lead to more convenient and cleaner
coding practices. Didn't PHP start as a language meant to be
user-friendly?
I don't actually work on the PHP engine, I just write RFC text for other people; I have ~25 years of experience writing user-space PHP. And no, anything involving stealth globals via statics is the opposite of "more convenient and cleaner."
--Larry Garfield
2024년 3월 30일 (토) 오전 1:21, Larry Garfield larry@garfieldtech.com님이 작성:
2024년 3월 29일 (금) 오후 10:21, Larry Garfield larry@garfieldtech.com님이 작성:
Hello.
I created a wiki for __callStatic related issues.
Please see:
https://wiki.php.net/rfc/complete_callstatc_magic
I look forward to your interest and advice.I am firmly against this proposal.
I think my objection boils down to this line in the RFC:
Of course, calling non-static methods in a static-like manner can be
confusing, but in modern PHP, it has already become common practice.I would argue this statement is false. Calling non-static methods in a
static-like manner is confusing, which is why in modern PHP one should
never do that, and respect that static and non-static methods exist in a
separate universe. Static methods are methods on a type. Non-static
methods are methods on an instance. Those are not the same thing.[1]It would be more accurate to say "calling non-static methods in a
static-like manner is common in Laravel," where the badly-named "facades"
system serves as a poorly designed, hard to debug, hard to test, archaic
alternative to using dependency injection. While there may have once been
an argument that DI was "too hard" for simple cases a decade ago or more
(though even then I think it was a bade trade-off), the combination of
auto-wiring DI Containers (which Laravel pioneered in PHP) and constructor
promotion (introduced in PHP 8.0, 3.5 years ago.) completely eliminates
those arguments. The level of effort to do actual DI today is trivially
small, and the benefits over magic hidden globals are massive.Laravel Facades are a relic of an older time best avoided, even in
Laravel projects. (I am far from the only person to argue this; many even
within Laravel's inner community make this argument.)Adding features to the language that seemingly exist only to make that
particular buggy hack easier to do is a step backwards, and I would argue
harmful for the language. On the contrary, I would favor going the other
direction: Calling a static method as though it were non-static currently
works, and I would support making that an error, to further emphasize that
static and non-static methods are not interchangeable.[1] https://peakd.com/hive-168588/@crell/cutting-through-the-static
--Larry Garfield
Thank you for your feedback.
I agree that static and non-static should be distinct, which is a given.There are a few points I'd like to make.
First, my proposed RFC is not about allowing non-static methods to be
used statically. Although all my examples use::
, they internally
operate on an instance. Inside__callStatic
, an instance is created
and used for operations.Second, as already possible through the
__callStatic
method,
non-static methods can be called as if they were static (as mentioned,
this does not mean they operate statically). For protected and private
methods, the__callStatic
function is invoked even for non-static
methods. This might not be to everyone's liking, and to others, it
might be a favorite feature. It might operate differently from the
initial intention when__callStatic
was introduced. However, I don't
think this is necessarily a bad thing. Isn't it developers who bring to
life ingenious ideas that were unforeseen?Developers also bring to life horrible monstrosities that are an afront to
all that is holy. I am a developer. It's what we do. :-) Especially when
VC money is involved.Not all "innovation" is good.
Third, as you can see from my examples, what I propose could be a
solution to the current issues. Since it does not work for public
methods while it does for protected and private ones, it has led to
code becoming more obscure and layered through facade-like patterns.
It's like taking a longer route because the road is blocked, or
creating a dog door because the main door is closed.It simplifies a practice that should not be a practice in the first
place. That's not a net-win.From the perspective of those who develop the PHP language itself, my
proposal might not be appealing. However, I believe from the user's
standpoint, my proposal could lead to more convenient and cleaner
coding practices. Didn't PHP start as a language meant to be
user-friendly?I don't actually work on the PHP engine, I just write RFC text for other
people; I have ~25 years of experience writing user-space PHP. And no,
anything involving stealth globals via statics is the opposite of "more
convenient and cleaner."--Larry Garfield
Hi.
It would be more accurate to say "calling non-static methods in a
static-like manner is common in Laravel
It might be correct to say that this is specific to Laravel. The problem,
however, is that Laravel is used so extensively that it cannot be ignored.
There's a point of embarrassing me. It's as if my proposal, if accepted,
would create problems that did not previously exist. Yet, the existence of
__callStatic
already allows for the issues you've pointed out to occur.
You can already write code like foo::bar()::baz()
with the current PHP.
The possibility of more problems arising could indeed be true. In that
sense, I understand your point.
And unless __callStatic
is intentionally used, calling non-static methods
statically will still result in an error, just as it does now.
I am simply proposing to give users the choice when they intentionally use
__callStatic
.
Daddyofsky
It would be more accurate to say "calling non-static methods in a static-like manner is common in Laravel
It might be correct to say that this is specific to Laravel. The
problem, however, is that Laravel is used so extensively that it cannot
be ignored.
True, but as someone else noted, Laravel already has a workaround in place for this. WordPress is orders of magnitude more popular than Laravel, but we don't generally design the language to work "the WordPress way," because that is well-recognized as a not-good way to work.
Popularity matters, but quality matters more.
There's a point of embarrassing me. It's as if my proposal, if
accepted, would create problems that did not previously exist. Yet, the
existence of__callStatic
already allows for the issues you've
pointed out to occur. You can already write code like
foo::bar()::baz()
with the current PHP. The possibility of more
problems arising could indeed be true. In that sense, I understand your
point.
To be clear: I have no interest or desire to embarrass you personally. I have never met you before so have no opinion about you one way or another, and trust the feeling is mutual. That you're interested in improving PHP is to your credit, and I thank you for that.
However, that is separate from the proposal itself, which for reasons stated I think is not a good one. That should not reflect on you personally in any way, and is explicitly not intended as such. Certainly I've had enough of my proposals rejected around here. :-)
--Larry Garfield
2024년 4월 1일 (월) 오전 2:31, Larry Garfield larry@garfieldtech.com님이 작성:
It would be more accurate to say "calling non-static methods in a
static-like manner is common in LaravelIt might be correct to say that this is specific to Laravel. The
problem, however, is that Laravel is used so extensively that it cannot
be ignored.True, but as someone else noted, Laravel already has a workaround in place
for this. WordPress is orders of magnitude more popular than Laravel, but
we don't generally design the language to work "the WordPress way," because
that is well-recognized as a not-good way to work.Popularity matters, but quality matters more.
There's a point of embarrassing me. It's as if my proposal, if
accepted, would create problems that did not previously exist. Yet, the
existence of__callStatic
already allows for the issues you've
pointed out to occur. You can already write code like
foo::bar()::baz()
with the current PHP. The possibility of more
problems arising could indeed be true. In that sense, I understand your
point.To be clear: I have no interest or desire to embarrass you personally. I
have never met you before so have no opinion about you one way or another,
and trust the feeling is mutual. That you're interested in improving PHP
is to your credit, and I thank you for that.However, that is separate from the proposal itself, which for reasons
stated I think is not a good one. That should not reflect on you
personally in any way, and is explicitly not intended as such. Certainly
I've had enough of my proposals rejected around here. :-)--Larry Garfield
I understand.
I didn't assume my proposal would be accepted without question. I just
started because I hate doing nothing.
Daddyofsky
On the contrary, I would favor going the other direction: Calling a static method as though it were non-static currently works, and I would support making that an error, to further emphasize that static and non-static methods are not interchangeable.
It's side-tracking, but I'd like to note that I would vote against such
an idea.
I don't have a strong opinion on the proposed RFC yet.
--
Aleksander Machniak
Kolab Groupware Developer [https://kolab.org]
Roundcube Webmail Developer [https://roundcube.net]
PGP: 19359DC1 # Blog: https://kolabian.wordpress.com
Hello.
I created a wiki for __callStatic related issues.
Please see:
https://wiki.php.net/rfc/complete_callstatc_magicI look forward to your interest and advice.
Best Regards.
Daddyofsky
Hey there,
Some general feedback:
The RFC is a bit hard for me to follow, for example:
However, the IDE cannot find active method, and the Go to Definition feature cannot be used.
This sounds like a bug or feature request with your IDE, not a problem with PHP.
This code is very clear, aside from the fact that the method is not static.
Clear to whom? As a developer this looks downright confusing. I can't
even guess what the actual behavior is. If you call a non-static
method statically, its currently an error. Why would this not be an
error?
The IDE recognizes active methods well and the Go to definition feature also works properly.
What is stopping the IDE to taking you to the __callStatic method?
That would be the correct behavior IMHO, not the implementation for
instance methods.
Even if there are only a few core methods, it cannot be made into a single file.
There is nothing stopping you from putting multiple classes in a file.
As can be seen in the above examples, the code becomes clearer, and navigation through the IDE works much better.
I completely disagree. It mixes concerns and makes spaghetti code into
incomprehensible code. Also, maybe you should take up IDE navigation
with your IDE?
Instead of throwing an error when a non-static public method is called statically, the _ _callStatic method should be invoked.
I completely agree with this, btw. Your examples could use some work
and shows all the reasons why it shouldn't call __callStatic(). A real
life example, that has nothing to do with a specific framework:
When generating proxies for existing types, you often need to share
some state between the proxies. To do that, you put static
methods/properties on the proxy class and hope to the PHP Gods that
nobody will ever accidentally name something in their concrete class
with the name you chose for things. To help with that, you create some
kind of insane prefix. If __callStatic() were called ALWAYS in a
static context, even if a non-static method exists, then collisions
would literally be impossible. But at that point, why can't I just
write:
class Test {
public static function test(): string { return "hello world"; }
public function test(): int { return random_int()
; }
}
??? I feel like this is your real RFC and should be allowed if we're
allowed to __callStatic() to instance methods. I don't think it makes
sense to have one without the other, and then what you want with
__callStatic() comes naturally, instead of this weird and confusing
RFC.
Robert Landers
Software Engineer
Utrecht NL
2024년 3월 30일 (토) 오전 2:15, Robert Landers landers.robert@gmail.com님이 작성:
Hello.
I created a wiki for __callStatic related issues.
Please see:
https://wiki.php.net/rfc/complete_callstatc_magicI look forward to your interest and advice.
Best Regards.
DaddyofskyHey there,
Some general feedback:
The RFC is a bit hard for me to follow, for example:
However, the IDE cannot find active method, and the Go to Definition
feature cannot be used.This sounds like a bug or feature request with your IDE, not a problem
with PHP.This code is very clear, aside from the fact that the method is not
static.Clear to whom? As a developer this looks downright confusing. I can't
even guess what the actual behavior is. If you call a non-static
method statically, its currently an error. Why would this not be an
error?The IDE recognizes active methods well and the Go to definition feature
also works properly.What is stopping the IDE to taking you to the __callStatic method?
That would be the correct behavior IMHO, not the implementation for
instance methods.Even if there are only a few core methods, it cannot be made into a
single file.There is nothing stopping you from putting multiple classes in a file.
As can be seen in the above examples, the code becomes clearer, and
navigation through the IDE works much better.I completely disagree. It mixes concerns and makes spaghetti code into
incomprehensible code. Also, maybe you should take up IDE navigation
with your IDE?Instead of throwing an error when a non-static public method is called
statically, the _ _callStatic method should be invoked.I completely agree with this, btw. Your examples could use some work
and shows all the reasons why it shouldn't call __callStatic(). A real
life example, that has nothing to do with a specific framework:When generating proxies for existing types, you often need to share
some state between the proxies. To do that, you put static
methods/properties on the proxy class and hope to the PHP Gods that
nobody will ever accidentally name something in their concrete class
with the name you chose for things. To help with that, you create some
kind of insane prefix. If __callStatic() were called ALWAYS in a
static context, even if a non-static method exists, then collisions
would literally be impossible. But at that point, why can't I just
write:class Test {
public static function test(): string { return "hello world"; }
public function test(): int { returnrandom_int()
; }
}??? I feel like this is your real RFC and should be allowed if we're
allowed to __callStatic() to instance methods. I don't think it makes
sense to have one without the other, and then what you want with
__callStatic() comes naturally, instead of this weird and confusing
RFC.Robert Landers
Software Engineer
Utrecht NL
Hello.
I'm not very familiar with documentation. It would be helpful if you could
suggest how to fix the problematic parts.
Using the example of the IDE meant to illustrate that it should be
intuitive enough for the IDE to find it directly.
Even currently, __callStatic
is called in cases of non-static methods
that are not public methods. __callStatic
already acts as a rule-breaker.
It seems like there's a desire for the magic method to be named as such
without actually causing much magic. The current __callStatic
is like a
magician who can use high-level magic to hit targets behind doors or
invisible targets but can't use basic magic to hit a visible door.
While it's good that the PHP kindly notifies errors, I think it would also
be beneficial to provide users with options to do other things,
specifically when they intentionally use __callStatic
. That's the core
point of this proposal.
If there are better examples or ways to explain, I would appreciate
learning about them.
Daddyofsky
Even currently,
__callStatic
is called in cases of non-static methods
that are not public methods.__callStatic
already acts as a
rule-breaker.
I think the problem here is a confusion based on the idea that there is
necessarily some direct correspondence between method names and strings
passed to __callStatic. It's like confusing URLs with file paths.
The fact that an object may have a private method named "foo" doesn't
have any bearing on whether classname::foo() invokes __callStatic('foo')
or not. The existence or otherwise of such methods in the class is
irrelevant. __callStatic receives a string, and what it does with that
string is entirely up to whoever is writing it.
class First {
protected static function test(): string {
return "Calling First::test\n";
}
}
class Second extends First
{
public static function __callStatic(string $name, array $args): string {
return "Calling callStatic::$name\n";
}
public static function pass(): string {
return Second::test(); // The inherited method
}
}
echo Second::pass();
echo Second::test(); // Not the inherited method
2024년 3월 30일 (토) 오전 2:15, Robert Landers landers.robert@gmail.com님이 작성:
Hello.
I created a wiki for __callStatic related issues.
Please see:
https://wiki.php.net/rfc/complete_callstatc_magicI look forward to your interest and advice.
Best Regards.
DaddyofskyHey there,
Some general feedback:
The RFC is a bit hard for me to follow, for example:
However, the IDE cannot find active method, and the Go to Definition feature cannot be used.
This sounds like a bug or feature request with your IDE, not a problem with PHP.
This code is very clear, aside from the fact that the method is not static.
Clear to whom? As a developer this looks downright confusing. I can't
even guess what the actual behavior is. If you call a non-static
method statically, its currently an error. Why would this not be an
error?The IDE recognizes active methods well and the Go to definition feature also works properly.
What is stopping the IDE to taking you to the __callStatic method?
That would be the correct behavior IMHO, not the implementation for
instance methods.Even if there are only a few core methods, it cannot be made into a single file.
There is nothing stopping you from putting multiple classes in a file.
As can be seen in the above examples, the code becomes clearer, and navigation through the IDE works much better.
I completely disagree. It mixes concerns and makes spaghetti code into
incomprehensible code. Also, maybe you should take up IDE navigation
with your IDE?Instead of throwing an error when a non-static public method is called statically, the _ _callStatic method should be invoked.
I completely agree with this, btw. Your examples could use some work
and shows all the reasons why it shouldn't call __callStatic(). A real
life example, that has nothing to do with a specific framework:When generating proxies for existing types, you often need to share
some state between the proxies. To do that, you put static
methods/properties on the proxy class and hope to the PHP Gods that
nobody will ever accidentally name something in their concrete class
with the name you chose for things. To help with that, you create some
kind of insane prefix. If __callStatic() were called ALWAYS in a
static context, even if a non-static method exists, then collisions
would literally be impossible. But at that point, why can't I just
write:class Test {
public static function test(): string { return "hello world"; }
public function test(): int { returnrandom_int()
; }
}??? I feel like this is your real RFC and should be allowed if we're
allowed to __callStatic() to instance methods. I don't think it makes
sense to have one without the other, and then what you want with
__callStatic() comes naturally, instead of this weird and confusing
RFC.Robert Landers
Software Engineer
Utrecht NLHello.
I'm not very familiar with documentation. It would be helpful if you could suggest how to fix the problematic parts.
Using the example of the IDE meant to illustrate that it should be intuitive enough for the IDE to find it directly.
Even currently,
__callStatic
is called in cases of non-static methods that are not public methods.__callStatic
already acts as a rule-breaker. It seems like there's a desire for the magic method to be named as such without actually causing much magic. The current__callStatic
is like a magician who can use high-level magic to hit targets behind doors or invisible targets but can't use basic magic to hit a visible door.While it's good that the PHP kindly notifies errors, I think it would also be beneficial to provide users with options to do other things, specifically when they intentionally use
__callStatic
. That's the core point of this proposal.If there are better examples or ways to explain, I would appreciate learning about them.
Daddyofsky
My main issue with the RFC comes down to the fact that it suggests
that this is valid:
// https://3v4l.org/0ufkt
class Test {
public function test() {}
public static function test() {}
}
Having two functions with the same name, one static and one non-static
is (currently) an error. Allowing callStatic to break this rule
without being able to write the above code, feels inconsistent. While
PHP is full of inconsistencies, adding more of them isn't the right
way. I'd much rather see static and non-static methods being able to
have the same name -- in which case it would make sense for callStatic
to work as described in the RFC.
Robert Landers
Software Engineer
Utrecht NL
When generating proxies for existing types, you often need to share
some state between the proxies. To do that, you put static
methods/properties on the proxy class and hope to the PHP Gods that
nobody will ever accidentally name something in their concrete class
with the name you chose for things. To help with that, you create some
kind of insane prefix.
Separating static and non-static methods wouldn't solve this - the
concrete class could equally add a static method with the same name but
a different signature, and your generated proxy would fail to compile.
In fact, exactly the same thing happens with instance methods in testing
libraries: test doubles have a mixture of methods for configuring mock /
spy behaviour, and methods mimicking or forwarding calls to the real
interface / class. Those names could collide, and require awkward
workarounds.
In a statically typed language, a concrete class can have two methods
with the same name, but different static types, e.g. when explicitly
implementing interfaces. In a "duck typing" system like PHP's, that's
much trickier, because a call to $foo->bar() doesn't have a natural way
to choose which "bar" is meant.
I'd much rather see static and non-static methods being able to
have the same name
Allowing this would lead to ambiguous calls, because as others have
pointed out, :: doesn't always denote a static call. Consider this code:
class Test {
public function test() { echo 'instance test'; }
public static function test() { echo 'static test'; }
}
class Test2 extends Test {
public function runTest() { parent::test(); }
}
(new Test2)->runTest();
Currently, this can call either of the test() methods if you comment the
other out: https://3v4l.org/5HlPE https://3v4l.org/LBALm
If both are defined, which should it call? And if you wanted the other,
how would you specify that? We would need some new syntax to remove the
ambiguity.
Regards,
--
Rowan Tommins
[IMSoP]
I created a wiki for __callStatic related issues.
Please see:
https://wiki.php.net/rfc/complete_callstatc_magic
Hi,
Several times in the discussion you have said (in different words)
"__callStatic is called for instance methods which are private or
protected", but that is not how it is generally interpreted.
If you are calling a method from outside the class, as far as you're
concerned only public methods exist; private methods are, by definition,
hidden implementation details. This is more obvious in languages with
static typing, where if you have an instance of some interface, only the
methods on that interface exist; the concrete object might actually have
other methods, but you can't access them.
That is what is meant by "inaccessible": __call and __callStatic are
called for methods which, as seen from the current scope, do not exist.
You could still argue that static context is like a different scope, or
a different statically typed interface - as far as that context is
concerned, only static methods exist. But that's also not a common
interpretation, for (at least) two reasons:
Firstly, there is no syntax in PHP which specifically marks a static
call - Foo::bar() is used for both static calls, and for forwarding
instance calls, most obviously in the case of parent::foo().
Secondly, until PHP 8, marking a method as static was optional; an error
was only raised once you tried to access $this in a context where it
wasn't defined. In PHP 4, this was correct code; in PHP 5 and 7, it
raised diagnostics (first E_STRICT, later E_DEPRECATED) but still ran
the method:
class Foo {
function bar() {
echo 'Hello, World!';
}
}
Foo::bar();
I think that's part of the reason you're getting negative feedback: to
you, the feature seems like an obvious extension, even a bug fix; but to
others, it seems like a complete change to how static calls are interpreted.
Regards,
--
Rowan Tommins
[IMSoP]