If by now I understood a little in ststic Now I realize I do not understand anything. I'm so confused and I struggle to understand and I can not. Someone can explain this program when using self, parent, static and how
All the smallest change I do changes the result without that I can not understand what's going on.
thanks a lot ..
the code from http://docs.php.net/language.oop5.late-static-bindings
<?php
class A {
public static function foo() {
static::who();
}
public static function who() {
echo __CLASS__."\n";
}
}
class B extends A {
public static function test() {
A::foo();
parent::foo();
self::foo();
}
public static function who() {
echo __CLASS__."\n";
}
}
class C extends B {
public static function who() {
echo __CLASS__."\n";
}
}
C::test();
?>
The out put are:
A
C
C
You'll need to understand the concept of Late Static Binding, which determines when an identifier is bound to code/data. You can tell PHP to bind it early (self::) or later (static::).
Slimming the example down to two classes we get:
class A {
public static function foo() {
self::who(); // PHP binds this to A::who() right away
static::who(); // PHP waits to resolve this (hence, late)!
}
public static function who() {
echo __CLASS__."\n";
}
}
class B extends A {
public static function test() {
self::foo();
}
public static function who() {
echo __CLASS__."\n";
}
}
B::test();
Look at http://php.net/manual/en/language.oop5.static.php. It says:
Declaring class properties or methods as static makes them accessible without needing an instantiation of the class.
...
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.
You cannot use $this because when calling a static method, there is no instantiated class object to be placed in the $this variable. So you use self::.
parent:: is referring to the parent class that the current class is extending. For example, for Class C the parent class is Class B, and for Class B, the parent class is Class A. See http://php.net/manual/en/keyword.parent.php.
You use static methods when you want the function to be accessible without actually having an instance of that class declared.
Upon closer inspection of your question, your link points to Late Static Bindings. The first two examples in that page pretty clearly indicate the need for the static:: syntax, but to clarify for the example you posted:
Take a look at the foo() method in Class A. It calls static::who(). This means that the method who() will be called in the scope of the class that called the function, instead of the scope of the class where the function is defined. So if you were to call C::foo(), it would echo C.
If, instead, it called self::who(), it would be calling A::who(). Because within Class A, self:: refers to A.
Hopefully that helps.
The key to the answer is static::who(), remember static:: means you call the method with the actual class (in our case - C).
so C::test() run as follows:
A::foo(); -> calls to A::foo() therefor echo A
parent::foo(); -> calls to C parent (which is B), B::foo() inherits A::foo() which calls to static::who(), but our actual class is C, therefor echo C
self::foo(); -> again calls to foo() which calls to static::who() with our actual class C
if instead of static::who() foo was calling self::who() you would have get three A as a result.
When one inherited class call inherit class's method which methods are use these key word; what will happened!! Explained by this flowchart. I think it will help.
Related
So I've been reading official PHP documentation on Late Static Bindings and came across a confusing example:
<?php
class A {
private function foo() {
echo "success!\n";
}
public function test() {
$this->foo();
static::foo();
}
}
class B extends A {
/* foo() will be copied to B, hence its scope will still be A and
* the call be successful */
}
class C extends A {
private function foo() {
/* original method is replaced; the scope of the new one is C */
}
}
$b = new B();
$b->test();
$c = new C();
$c->test(); //fails
?>
The output of the example:
success!
success!
success!
Fatal error: Call to private method C::foo() from context 'A' in /tmp/test.php on line 9
Can someone please explain why the private method foo() gets copied to B? As far as I know only public and protected properties get copied to child class. What am I missing?
Maybe the comment "foo() will be copied to B" is a bit confusing or interpreted incorrectly. foo() is still private to A and can only be accessed from methods within A.
ie. In the example if you try to execute$b->foo() its will still fail as expected.
This is as I explained the example to myself and maybe will be helpful for others:
Considering class B.
$b->test() is able to access foo() as a public member of A.
$this->foo() also succeeds within $b->test()
$static::foo() succeeds because it is calling the version of foo() defined in A, from test() which is also defined in A. No scoping conflict.
Considering class B.
When foo() is overridden in class C,
$c->test() of course is still accessible as a public member if A.
and within $c->test() $this->foo() is accessible as a private member of A. - all good.
BUT
$static::foo() is now trying the access from A, the version of foo() defined in class C and so fails because it is private in C. - as per the error message.
I'm having a hard time trying to understand the output of the following code:
class Bar
{
public function test() {
$this->testPublic();
$this->testPrivate();
}
public function testPublic() {
echo "Bar::testPublic\n";
}
private function testPrivate() {
echo "Bar::testPrivate\n";
}
}
class Foo extends Bar
{
public function testPublic() {
echo "Foo::testPublic\n";
}
private function testPrivate() {
echo "Foo::testPrivate\n";
}
}
$myFoo = new foo();
$myFoo->test();
Output:
Foo::testPublic
Bar::testPrivate
Class Foo overrides testPublic() and testPrivate(), and inherits test(). When I call test(), there is an explicit instruction envolving $this pseudo variable, so after I created $myFoo instance, the final calls of test() function would be $myFoo->testPublic() and $myFoo->testPrivate(). The first output is as I expected, since I overrode testPublic() method to echo Foo::testPublic. But the second output makes no sense to me. Why is it Bar::testPrivate if I overrode testPrivate() method? Also the private method from parent class wouldn't be inherited anyway, by definition! It makes no sense. Why is the parent method the one being called???
The problem with your code is that the method Bar::testPrivate is private, therefore it cannot be overridden by child classes. For starters, I recommend that you read up on visibility in PHP - http://www.php.net/manual/en/language.oop5.visibility.php. There you will learn that only public and protected class member methods/properties can be overridden, private ones cannot.
As a good example, try changing the visibility of the Bar::testPrivate method to either public or protected, without altering anything else in your example code. Now try and run your tests. What happens? This:
PHP Fatal error: Access level to Foo::testPrivate() must be protected (as in class Bar) or weaker
The big question is: "why?". Well, you have now overridden Bar::testPrivate with a private Foo:testPrivate. This new private method is out of scope for Bar::test, because private class members are visible to their current class only, NOT the parent/child classes!
Therefore, as you can see, OOP provides a certain amount of encapsulation for class members, and it can be quite confusing if you don't take the time to understand it.
While studying Late Static Binding in PHP , i read the below quotations:
A “forwarding” call is a static call that is introduced by parent::, static:: or one called
by the function forward_static_call().
A call to self:: can also be a forwarding call if the class falls back to an inherited
class because it does not have the method defined
Late static binding works by storing the class in the last “non-forwarding call”. In
other words, late static binding resolution will stop at a fully resolved static call.
According to the cited two points , look at the below example :
class A {
public static function foo() {
echo static::who();
}
public static function who() {
return 'A';
}
}
class B extends A {
public static function test() {
self::foo();//this is non forward call because self will resolve to the current class because it has the function foo , so now the last stored class name of non forward call became B , then now the foo will be called and static must resolve to B not C.
}
public static function foo() {
echo static::who();
}
public static function who() {
return 'B';
}
}
class C extends B {
public static function who() {
echo 'C';
}
}
C::test(); //
At the point of self::foo() , self here is non-forwarding call because the class itself has the invoked function foo (which is the cited rule in above quotations) and according to the concept of Late Static Binding which stores class name of the last non-forwarding call, so now B is the last saved referenced class name, so now static in foo() must resolve to B, not C.
So, How do this wrong and static resolves to the initial non-forwarding call not the last?
Ref: PHP Zend Certification Study Guide.pdf.
The quote contains the answer:
A call to self:: can also be a forwarding call if the class falls back to an inherited class because it does not have the method defined
In test you are calling foo which doesn't exist in class C, so the class falls back to inherited class B, and self:: will forward the calling information.
There is a similar exemple in the page for Late Static Binding (example #4) accompanied by a similar note:
Late static bindings' resolution will stop at a fully resolved static call with no fallback. On the other hand, static calls using keywords like parent:: or self:: will forward the calling information.
class Person {
function foo() {
// Code.
}
function bar() {
$this->foo();
}
}
class Pete extends Person {
}
When Person::foo() is called from within Person::bar() in the above example, the call is happening within the Person class. Hence, I could make the visibility of Person::foo() private.
As you'll be aware, when I extend the Person class, Person::foo() and Person::bar() are inherited by the child class Pete. Hence, the inherited method Pete::bar() calls Pete::foo().
My question
From within Pete::bar(), is the call to Pete::foo() considered to come from a) the parent class or b) the child class?
If a method has a visibility of private, then all code which explicitly calls it must reside in the same class definition. That's pretty much the rule, nothing more, nothing less. Indirect calls through inheritance work just fine.
class Foo {
private function bar() { }
public function baz() { /* here be dragons */ }
}
class Child extends Foo { }
In the Child class you may not write $this->bar(). It will fail. The bar method is private to the class Foo, no other code may call it. You may call baz though anytime from anywhere, it is public and can be called from other code. Whatever baz does internally is none of your concern. If baz calls bar internally, that's fine. Its code resides in Foo and therefore can call bar.
From within Pete::bar(), is the call to Pete::foo() considered to come from a) the parent class or b) the child class?
Neither. Technically, foo() does not exist in class Pete. It exists in Person and is inherited by Pete. Regardless, who's calling the method is based on the invocation.
For example:
$person = new Person();
$person->foo(); // invocation by `Person` object
$pete = new Pete();
$pete->foo(); // invocation by `Pete` object
I'm trying to determine method visibility
If you want these methods to be inherited, you are limited to public or protected. private methods are not inherited. I would encourage you to read more about visibility.
As noted in deceze's answer, you can make methods private and access it through another public method.
If you make it private, Person::foo can only be called from Person
class Person {
//Can only be called inside of Person
private function foo() {
// Code.
}
public function bar() {
//can be called
$this->foo();
}
}
You can still call bar, since it is public. bar still can access to foo, because it is a method from Person.
You can not call foo from Pete, since it is only visible in Person.
class Pete extends Person {
public function doSomething() {
//Works because bar itself calls foo
$this->bar();
}
}
If you want to call foo directly fom Pete or override it, you need to declare it protected instead of private.
I'm attempting to access member variables in a child class via the parent class without instantiation.
This is one of my attempts but B::getStatic() fails with Access to undeclared static property.
Is there another solution to this, possibly without static?
class A {
static public function getStatic() {
return self::$myStatic;
}
}
class B extends A {
public static $myStatic = 5;
}
class C extends A {
public static $myStatic = 6;
}
var_dump(B::$myStatic);
var_dump(B::getStatic());
var_dump(C::$myStatic);
var_dump(C::getStatic());
The concept you're running into is called "Late Static Binding." Until PHP 5.3.0, there was no support for this.
If you're running 5.3.0 or higher, update the getStatic() method:
static public function getStatic() {
return static::$myStatic;
}
The others are right, the way your code is it can't be done since the variable doesn't exist at compile time.
The way to do something like this is usually with an abstract class (available in PHP5 and up, it looks like).
Class A would be the abstract class, and would have a getStatic() function. Classes B and C would extend A and have definitions for the getStatic() function. This way, when you call getStatic() you will get the value the subclass defines since there is no definition in A.
The caveat to this approach is that you can't instantiate A since it's abstract. You would ALWAYS have to make a B or a C (or a subclass there-of).
You could also make a setter in A and have the subclasses use it to set the value (instead of an '='s). That would let you instantiate A and it could set the value if it ever needs to. You might be able to make the setter private so it can't be called directly, I don't know if subclasses can use private functions in PHP.
You have a mismatch between the declaration of the function and variable.
Either you need to move the declaration of the function to B
or
move the declaration of the variable to A.
Class B inherits the properties from class A instead of the reverse.
Why don’t you use B::$myStatic like in your example?
You have to move myStatic into A. Your method getStatic in A can't access a variable that does not exist in A.
From the PHP manual:
Static references to the current class
like self:: or __CLASS__ are resolved
using the class in which the function
belongs, as in where it was defined:
So because the method is defined in A, when you call getStatic() on B or C it is trying to return a::$myStatic, which doesn't exist. Even if it did exist you would only ever get that value back, not any overridden value in a subclass.
A solution is Late Static Bindings, but this is only available in PHP 5.3 which is not yet released.
$myStatic must be declared static in class A: See here.
class A {
public static $myStatic = 5;
}
class B extends A {
public static $myStatic = 3;
}
class C extends A {
public static $myStatic = 1;
}
Then just use B::$myStatic ...