I saw this in the PHP OOP manual http://www.php.net/manual/en/language.oop5.visibility.php and I can't get my head around why the output is not: Foo::testPrivate Foo::testPublic
class Bar
{
public function test() {
$this->testPrivate();
$this->testPublic();
}
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(); // Bar::testPrivate
// Foo::testPublic
It's all about the visibility of the variables / methods.
You'll notice that in the Bar class, the method testPrivate() is private. That means that ONLY itself can access that method. No children.
So when Foo extends Bar, and then asks to run the test() method, it does two things:
It overrides the testPublic() method because it's public, and Foo has the right to override it with it's own version.
It calls test() on Bar (since test() only exists on Bar()).
testPrivate() is not overridden, and is part of the class that holds test(). Therefore, Bar::testPrivate is printed.
testPublic() is overridden, and is part of the inheriting class. Therefore, Foo::testPublic is printed.
In some cases, it is easy to notice that you want a private method on the Bar class, but you also wants the Foo class to access it.
But wait, it is public or private?
Here comes the protected modifier.
When a method is private, only the class itself can call the method.
When a method is public, everyone can call it, like a free party.
When a method is protected, the class itself can call it and also whoever inhered this method (children) will be able to call it as a method of their own.
I posted the same question few days ago... because this behaviour wasnt logical for me either.
$this is always referred to the current object which it is used in. In my opinion example like this should throw an error or warning or something. Because in the above example you are actually accessing private members :SSS WHICH SUPPOSED TO BE INACCESSIBLE!
Related
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.
From PHP mannual second paragraph, it says that:
static:: introduces its scope.
I tried the following example accordingly:
class Father {
public function test(){
echo static::$a;
}
}
class Son extends Father{
protected static $a='static forward scope';
public function test(){
parent::test();
}
}
$son = new Son();
$son->test(); // print "static forward scope"
It works as described. However, the following example will raise a fatal error:
class Father {
public function test(){
echo static::$a;
}
}
class Son extends Father{
private static $a='static forward scope';
public function test(){
parent::test();
}
}
// print "Fatal erro: Cannot access private property Son::$a"
$son = new Son();
$son->test();
My main question is how to interpret the word scope here? If static introduces Son's scope to Father, then why private variables are still invisible to Father?
Are there two things variable scope and visibility scope? I'm new to PHP sorry if this sounds funny.
There are two things at play here: scope and visibility. Both together decide if you can access the property.
As you found in your first test, late static binding lets $a be available in the scope of the Father class. That simply means the variable (not necessarily its value) is "known" to this class.
Visibility decides whether the variables in scope can be accessed by particular classes and instances. A private property is only visible to the class in which it is defined. In your second example, $a is defined private within Son. Whether or not any other class is aware it exists, it can not be accessed outside of Son.
static makes $a a property which is known to Father, but the property's visibility decides whether or not its value can be accessed.
As a test to further help understand it, try using self instead of static. You'll get back a different error that $a is not a property of Father.
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.
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.
There was an interesting question in a practice test that I did not understand the answer to. What is the output of the following code:
<?php
class Foo {
public $name = 'Andrew';
public function getName() {
echo $this->name;
}
}
class Bar extends Foo {
public $name = 'John';
public function getName() {
Foo::getName();
}
}
$a = new Bar;
$a->getName();
?>
Initially, I thought this was produce an error because static methods can not reference $this (atleast in PHP5). I tested this myself and it actually outputs John.
I added Foo::getName(); at the end of the script and did get the error I was expecting. So, what changes when you call a static method from within a class that extends the class you're calling from?
Would anyone mind explaining in detail exactly what is going on here?
Foo::getName() is using an older PHP4 style of scope resolution operator to allow an overridden method to be called.
In PHP5 you would use parent::getName() instead
It's useful if you want to extend, rather than completely override the behaviour of the base class, e.g. this might make it clearer
class Bar extends Foo {
public $name = 'John';
public function getName() {
echo "My name is ";
parent::getName();
}
}
If you call the static method bound to the other object, the method is executed in the context of the current object. Which allows access to the $this-object.
Better way to call the superclass-method from inside the subclass would be:
parent::getName();
$this to the object in whose context the method was called. So: $this is $a->getName() is $a. $this in $fooInstance->getName() would be $fooInstance. In the case that $this is set (in an object $a's method call) and we call a static method, $this remains assigned to $a.
Seems like quite a lot of confusion could come out of using this feature. :)
When you call $a->getName() you're referencing a specific object, $a, which is of class Bar and so returns "John".
Foo::getName() isn't valid outside the function because there's no specific object.
I'm not sure it works in PHP, but if you cast the object to the superclass as in (Foo)$a->getName() then you'd get "Andrew" as your result. You'd still be talking about the specific object ($a) but in this case of type Foo. (Note you wouldn't generally want to do this)
Sometimes programmers are better at explaining things in code than in English!
The first thing going on here is the concept of overloading. When you instantiate Bar, it's getName() method overloads the method of the same name in Foo.
Overloading is a powerful and important part of OOD.
However, it is often useful to be able to call the version of a method that exists in the Parent class (Foo).
Here's an example:
class Dog
{
public function getTag()
{
return "I'm a dog.";
}
}
class Skip extends dog
{
public function getTag()
{
return Dog::getTag() . " My name is Skip.";
// I'm using Dog:: because it matches your example. However, you should use parent:: instead.
}
}
$o = new Skip();
echo $o->getTag(); // Echo's: "I'm a dog. My name is Skip."
Clearly this is a very parochial example but it illustrates a point.
Your base class is the most general implementation of a Type. In this case, it's "Dog." You want to put information in this base class that is common to all instances of that Type. This prevents duplication in each of the Derived classes (like "Skip").
Your script is taking advantage of this feature, perhaps inadvertently.