just like the __call magic method we can use in PHP to hook a call to a non defined method, is there a way to hook a call to an undefined constant or variable?
Like A::B, where B doesn't exist.
No. Constants are evaluated at opcode compile time not runtime, so there's no way to 'catch' them. There is still an issue with php related to this where a parent class cannot call a childs constant inside a parents method.
You're probably looking for __get and __set. I'm not really sure how it works with static constants though, you might only be able to work with instanced objects. See G-Nugget's comment regarding using them statically.
Related
I'm trying to build a tool that add/remove methods for me in a class, basically saving me the time to type some standard methods I use in my framework.
However, it seems to me that the getMethods method of the ReflectionClass uses some sort of cache, because if I call getMethods once, then change the methods dynamically (for instance replacing the class file with another one with the same class name but different methods), then call getMethods again, it doesn't take into account my dynamic changes.
I tried sleep, but it was obviously not that.
I was wondering if there is a way (but I'm afraid there is not) in php to "refresh" the ReflectionClass, so that it can "reflect" on the actual content rather than on some sort of cache.
As a work around, I can rely on tokens, but that requires a bit more work than just using the Reflection classes, so it would be great if I could "reset" the Reflection cache somehow.
With the constraints you have I dont see a way to do this natively.
Maybe you can consider using runkit https://www.php.net/manual/en/function.runkit-method-redefine.php because it would seem to be possible (and maybe it will suit your needs) but I'll stick to base PHP in my answer.
You never use reflection on a file, you use reflection on a class/function, etc. so on code level. And to use reflection on a class you have to declare it first (require, autoload, etc.) and once it is declared thats it, you cannot redeclare it. Trying to require file with the same class will result in an error.
So requiring a file with a class, using the class and then changing the file itself will have no effect. Take a look at the code:
<?php
file_put_contents('a.php', '<?php class A {function a() {return "a";}}');
require('a.php');
$a = new A();
var_dump($a->a());
file_put_contents('a.php', '<?php class A {function b() {return "b";}}');
$a = new A();
var_dump($a->b());
Not even mentioning reflection at this point - how would you make this code print 'b'? You will get PHP Fatal error: Uncaught Error: Call to undefined method A::b() in ... because defined version is still the one you required. Requiring file again will result in PHP Fatal error: Cannot declare class A, because the name is already in use in ....
So I think reflection is working correctly.
I'm working on old CodeIgniter 2 code that I can only change by adding a layer on top, so I'm limited.
Often in the code, a property $this->secondary_db is often called even before it was initialized, like such:
$this->secondary_db->get_all();
Which obviously end up with a Fatal error since secondary_db is null.
So, what I tried to do was implement the magic __get($name) method but ONLY for secondary_db so it would only use the magic method when $this->secondary_db is not defined by specifying in the magic method:
if ($name == 'secondary_db') { ... load db in a specific way ... }
However it creates other fatal errors from other bits of code somewhere that rely on __get() not being called, like such:
Indirect modification of overloaded property Some_Controller::$benchmark has no effect
Cannot assign by reference to overloaded object in system/core/Controller.php
Is there another way to do this or achieve the same thing that I might have forgotten about? Could traits be used for that?
NOTE: I cannot initialize secondary_db in the constructor since it's not always the same value.
I was looking at the codebird-php git and noticed that the author has a way to detect methods that are not declared in the class itself. For example, he has
$cb->statuses_homeTimeline();
which successfully executes, despite there not being a method called statuses_homeTimeline() in the Codebird class.
I've tried looking for information regarding this type of construction, but without knowing what it's called, I haven't found anything.
What is it generally called (I've googled all variations of "variable methods," "mapping methods," etc)? Are there arguments against its use? How does it (in principle) work?
I found a bunch of questions involving __call and things you can do with it, but nothing about what __call actually is.
PHP objects have a number of Magic Methods. The most well-known being __construct.
__call is a magic method which gets called whenever you try and call a method that doesn't exist. It's sort of a "catch-all" for methods.
The technical term is "Method Overloading".
So when $cb->statuses_homeTimeline() is called, if that method does not exist, it will instead call
$cb->__call("statuses_homeTimeline",array())
__call() magic method. __call() is triggered when invoking inaccessible methods in an object context.
To call a parent class (it has been instantiated) method I use
parent_class::method(); //tested it works
to call a method with in the instantiated class I am in I use
$this->method(); //tested it works
However if I call a static method from any class I use
parent_class::static_method(); //tested it works
I guess this makes since b.c. there is only one copy of a method per class, whether it is instantiated or not?
Can some one validate or provide insight to this. I just want to verify that the call method is the same for both static methods from any class and calls to a parent classes method.
Seems a bit strange.
The syntax is correct. Not exactly sure what your question is. If you wanted to call a static method defined in the child from within the child, you could use self::static_method() or $this->static_method(). Either would work.
In my company's codebase, i see functions used in both static and object context. For e.g. a class A has a function b() which is called both using A::b() and/or object_of_type_A->b(). I know this throws an error if strict is turned on. But I wanted to know if this is a bad practice and if yes, then why? Thanks for any answers.
Let me know if I don't make sense anywhere. I would be happy to clarify.
I'm not a php guy, but this sounds just like Java, where it's allowed but discouraged.
If it's static, I would strongly recommend only calling it in a static way. Otherwise it looks like it depends on the state of the object you're supposedly calling it on.
In Java the best example of this is Thread.sleep(). It's a static method which puts the current thread to sleep, always. But look at this code:
Thread t = new Thread(someTask);
t.start();
t.sleep(1000);
What does it look like that code is doing? It appears to be putting the other thread to sleep, whereas in fact it'll be the current thread that's sleeping. When you change it to a plain static call, it's more obvious:
Thread.sleep(1000);
That doesn't refer to t, so must be about the current thread.
Unless there's something specific to php where calling the static method via a variable gives you some sort of polymorphism, I suggest you stick to calling it in the static way. The fact that strict mode tells you to do this is a pretty strong hint, IMO :)
Here's some test code:
<?php
error_reporting(E_ALL | E_STRICT);
class Foo{
public function a(){
}
public static function b(){
}
}
$MyFoo = new Foo;
Foo::a(); // Strict Standards: Non-static method Foo::a() should not be called statically
Foo::b();
$MyFoo->a();
$MyFoo->b(); // No complaints
?>
PHP/5.3 warns about static calls to non-static methods, which is fine since they are subject to failure as soon as you want to access $this. But it does not complain about object context calls to static functions: there's nothing that can go wrong. This behaviour is documented:
Declaring class properties or methods
as static makes them accessible
without needing an instantiation of
the class. A property declared as
static can not be accessed with an
instantiated class object (though a
static method can)
[...]
Because static methods are callable
without an instance of the object
created, the pseudo-variable $this is
not available inside the method
declared as static.
So, as far as PHP is concerned, what you found in the code base is not wrong. However, I think it's slightly confusing.
There is 'currently' no harm in using it either way except of course when called as a static function you can't access the $this member.
The reason it errors in strict is because not writing your code to strict standards can result in errors occurring due to a lack of diligence. in the future it may also cause your code to break. a static function has no $this member and it may break parameter passing.
Play it safe only call static functions with A::b() type calls.
DC
Regarding accessing $this in a static function I found something a bit strange a while back (might be changed in later versions of PHP though, think I ran 5.2 or something).
You can read about it here but it's in swedish. But use google translate and it should be understandable.
http://www.phpportalen.net/viewtopic.php?p=560080#560080