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.
Related
I try to look at all the files in nesbot/carbon vendor source code but still can't find the implementation of some methods likes roundCentury, addDay, addDays... except the php docblock.
Because I want to know how these methods work.
I wonder where is implementation of these method?
Thanks in advance
The code structure of Carbon is rather complicated, including heavy use of PHP traits and a custom "macro" system, but eventually I tracked down the definition to Carbon\Traits\Date which is included into the main classes like Carbon\Carbon.
This doesn't define the methods directly, but rather implements method overloading via __call, where the method name is passed in as a string. The Carbon code actually parses the method name to decide what it should do.
For rounding, that calls roundMethod, which is defined in another trait, called Carbon\Traits\IntervalRounding, the main line of which is this:
return $this->{$action.'Unit'}(substr($method, \strlen($action)), ...$parameters);
For roundCentury, $action is "round", and the substr part takes the rest of the name, so you get:
return $this->roundUnit('Century', ...$parameters);
The definition of roundUnit is then in yet another trait, Carbon\Traits\Rounding.
The "add..." methods presumably work similarly.
A function with the name addDay is not listed in the sources of Carbon. It is therefore difficult to find the place where the actual action takes place. When addDay is called, the magic function __call() in Traits/Date.php becomes active. There it is split into an "add" action and a "Day" unit and branched to addUnit() method. There we will find the actual action:
$date = $date->modify("$value $unit");
round*** supports dynamically any unit, so there is no hard-coded method for each of them but one single method and __call() takes care to parse the method name and select the appropriate unit:
https://github.com/briannesbitt/Carbon/blob/b017c794d31626a324c8216ff222fb895306c911/src/Carbon/Traits/Rounding.php#L40
i have been reading about magic functions lately, and I'm really confused about their implementations. Some Magic functions such as __contruct() and __destruct() are very useful. Magic functions like __construct() could be used to initialize variables with default values.
However I'm really confused with the implementation of other magic functions such as __isset(), __call(), __toString(), etc. What is the actual purpose of implementing the Magic Functions.
Yes, I do understand they are invoked behind the scenes and do not require a function call, but then what is their main advantage in real world, in terms of security-sql injection-scope. The main difference between isset() and __isset() (or any other Magic Function) and the situations in which I should use them?
You shouldn't use magic methods in PHP unless you want some documented magic functionality.
They allow you to react to certain events when using these particular objects. This means when certain things happen to your object, you can define how it should react in that instance.
Each of these methods are triggered automatically and you are just defining what should happen under these circumstances.
Probably you won't ever need to use any of them besides __construct() and __destruct() when dealing with objects.
__construct() - Is called when an object is first created. You can inject parameters and dependencies to set your object up.
__destruct() - Is called when an object is destroyed. You can write some cleanup code here. Closing any open datastreams, database connections... whatever.
__get() - Listens for get requests of the properties.
__set() - Listens for set requests of the properties.
__isset() - Triggered by calling isset() or empty() on the object's properties.
__unset() - Triggered by calling unset() on the object's properties.
__toString() - Allows you to define how an object will behave when it's treated like a string.
__sleep() - Code defined here will run before you use serialize(). So you can define which properties of the object should be serialised.
__wakeup() - This is used to reinitialize any tasks that may have been put to stop during the serialization.
__invoke() - Defines how your class should behave if you "invoke" it and use it like a function.
__clone() - Triggered when cloning an object is finished. (If you copy your objects they are still linked to their original as they are still referencing it. Cloning can get you a clean copy.)
__debugInfo - Triggered when using var_dump() on the object. You can use it to control what kind of info should show up in the dump. If the method isn't defined on an object, then all public, protected and private properties will be shown.
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.
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