Late static bindings | static:: usage in a non-static context - php

Php manual for the late static bindings states, in the example of static usage in non-static context, that foo() will be copied to B? Is method inheritance copying with scope of the original function being maintained?
<?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

As far as I can say, this is a problem of scope. When a child class does not override a parent's class method and you call said method via the child class, you will be in the parent class's scope and have access to private methods of the parent class.
If you implement a test() method in the child class, you will have that scope when you call it and will not be able to access private methods of the parent class.
I would say that 'copy' is not a fitting term for what's happening because the parent methods are not copied, they are just available in the child class, given the right scope. That is, they don't take the scope of the child class, but keep their own. They are only accessible in the child class if set to protected (or public) or if you call private methods with the parent's scope (as described in your example).
More information from your linke here: Strange behavior when overriding private methods
The official documentation does not explain it explicitly, but I could find this:
Private methods of a parent class are not accessible to a child class. As a result, child classes may reimplement a private method themselves without regard for normal inheritance rules.

Related

Is Inheritance means copy from parent to child or the child gain access to the parent visible members? [duplicate]

This question already has answers here:
Is subclass inherits private members from parent class? [duplicate]
(2 answers)
Closed 5 years ago.
Accept my apologies for being beginner for OOP,
according to the below code :
Class Test{
private $name = "youhana";
function setPrivatePropFromInside(){
$this->name = "mina";
}
function getPrivate(){
var_dump(__CLASS__);
echo $this->name ;
}
}
Class Test2 extends Test {
}
$obj2 = new Test2();
$obj2->getPrivate();
My Question is that Is Inheritance means to copy from parent to child or the child gain access to the parent visible members?
let me describe why I have confusion by mentioning my thoughts with both of the question members :
In case its a copy, so the invoking the method getPrivate from the child object must return null because the private members will not be copied from the parent to the child, and also the CLASS constant must return Test2 not TEST in case the Inheritance means copying.
so the code mentioned above would equals :
Class Test{
private $name = "youhana";
function getPrivate(){
var_dump(__CLASS__);
echo $this->name ;
}
}
Class Test2 extends Test {
function getPrivate(){
var_dump(__CLASS__);
echo $this->name ;
}
}
In case Inheritance means to gain access to the parent visible members, that doesn't refer or point to the concept of inheritance (the children get the characteristics of the parent) despite this concept is logically correct with the results upon executing the mentioned code snippet.
I Read more than 20 References and I still have the confusion, and again accept my apologies for being beginner searching for the correct approach.
Note that: I asked a question Here but after studying more references, I have been returned back to the confusion again, so I need a solid answer.
It's nothing to do with "copying".... a class defines methods and properties together with a visibility indicating from where those methods and properties can be accessed.
When one class extends another, then you are creating an inheritence hierarchy or tree, or a set of class contexts.
When you instantiate a child class, you are actually instantiating an object that inherits that full tree.
When you call a method against that instance, it looks to see if that method exists (and is accessible) in the child class definition. If so, it executes it in that context: if not, it looks to see if the method exists in the parent class; and if so, will execute it in that context.
When a method executes in a specific context within the hierarchy of class extensions, it has access to everything visible in that context. Private properties are only accessible in the context where they are defined/the class where they are defined; but methods in that context/class have access to those private properties.
If (as in this case) your public getters and setters exist in the same class/context as the private property, then those methods have access to the private property (because they are in the same class/context), and can be used to access it from outside of that context because the getters/setters themselves are public.
Is Inheritance means copy from parent to child or the child gain
access to the parent visible members?
The child gain access to the visible members of parent class. Also, you get flexibility to override the feature (method) of parent class.
I think your confusion comes from thinking that
private $name = "youhana";
is a static value which exists in class declaration. In any case, that is just a shorthand for declaring variable values in constructor so even if inheritance "copy" from parent its a wrong example to show that. What you should be asking is: do static properties get copied from the parent? Static properties exists in class declaration and any modifications are visible to all objects of that class.
php docs on static properties
Answer is no. Only reference to parent's value is passed.
I wrote a simple example to illustrate
<?php
class Foo
{
public static $my_static = 'foo';
public function staticValue() {
return self::$my_static;
}
public function modifyFooStatic(){
return self::$my_static .= '+';
}
}
class Bar extends Foo
{
public function fooStatic() {
return self::$my_static;
}
public function modifyBarStatic(){
return self::$my_static .= '-';
}
}
$foo = new Foo();
$foo->modifyFooStatic();
print $foo->staticValue() . "\n"; // foo+
$bar = new Bar();
$bar->modifyBarStatic();
print $bar->fooStatic() . "\n"; // foo+-
?>
As you can see both child and parent modifies the same variable even if child calls it with sellf::$my_static

Inheritance and function calls parent and sub-class

I encountered the following structure:
// parent class
class A
{
public function myFunc1()
{
$this->myFunc2();
}
private function myFunc2()
{
echo "called from class A";
}
}
// sub-class
class B extends A
{
private function myFunc2()
{
echo "called from class B";
}
}
$foo = new B();
$foo->myFunc1();
I expected, since there is no myFunc1() in class B, that the parent-function is called. This seems to be correct.
Now, to play it safe, I var_dump $this in myFunc1() and it shows, that this is an object from type B.
From my understanding, it should call myFunc2() from the Class B, but this isn't happening. It is calling the method from class A.
called from class A
instead of
called from class B
Yes, the functions are private and if I change it to protected, it works as expected. But private implies, that I have access to this function(s), when I'm in the specific context, doesn't it?
Private functions are only available within the class they are defined in, not in sub classes.
This means that your Object has two completely different functions, that happen to have the same name. Object B is aware of having one of them while Object A is only aware of having the other one. They do not interact in any way.
Since these functions are entirely private to the specific class they were defined in, there is no way to override them, or for any other class to call them.
If you need behavior that allows you to override how the class works, you'll have to use protected instead, which is designed specifically to be callable and changeable from extensions (and as such is a completely different beast all-together).
private always belongs to the same class you can't inherit it. That's the reason why myFunc1() calls myFunc2() from class A. If you want to overwrite it you have to change the visibility to protected.

PHP: Interhited method calling a method in the parent class

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.

Method visibility when extending an abstract class in PHP

In my abstract class My_Class, I have a method My_Class::foo() that's called from within another method belonging to the class. For example:
abstract class My_Class {
function foo() {
// Stuff.
}
function bar() {
$this->foo();
}
// More methods etc...
}
Now, I'm in the process of extending my abstract class. For example:
class My_Class_Extended extends My_Class {
}
As you'll know, both My_Class::foo() and My_Class::bar() are inherited by My_Class_Extended.
I never want My_Class::foo() to be called outside of My_Class or My_Class_Extended so I know not to make its visibility public. My problem is, I'm unsure whether to make its visibility protected or private.
My question
Considering how I'm calling My_Class::foo() in the above scenario, should it be made protected or private? I'm not sure if the call to My_Class::foo() is coming from the child or parent class.
Thanks in advance.
One-line: protected, because you want your child classes have access
The visibility modifiers work like this:
public: visible from everywhere.
$c = new My_Class_Extended(); $c->thisIsPublic();. This doesn't work with private or protected
protected: visible inside of the class and it's child classes
You can only call these functions inside of a function belonging to a class that derives from your parent class, or the parent class itself.
private: Only visible for the class it's defined in. You cannot call private functions in child classes, nor outside of the class.
The modifiers are ordered inclusively. So a protected is more restrictive than public, and private is more restrictive than protected.
You want protected, because you want to call them inside a child class, but not outside of it.
By the way: In your context, the abstract keyword only ensures that you cannot create an instance from My_Class.

PHP magic __get not working for variable in abstract base class

In my project, I'm using class inheritance a lot.
Now I notice that my magic getter is not triggering when I want to access a variable in the base class.
Hence the following code:
abstract class A
{
protected $varA;
final public function __get($var)
{
echo $var;
}
}
class B extends A
{
protected $varB;
}
class C extends A
{
public function test()
{
$test = new B();
$test->varB; // Get output
$test->varA; // No output
}
}
$test = new C();
$test->test();
Now I see that you faced with php feature. Visibility of properties relies on classes but not on the objects.
Objects of the same type will have access to each others private and
protected members even though they are not the same instances. This is
because the implementation specific details are already known when
inside those objects.
http://php.net/manual/en/language.oop5.visibility.php#example-208
__get is only triggered if the property does not exist.
varA is a property of you object. The oly problem is that it is protected. thus not accessible from outside your class.
From CHILD class protected var is available. Child class see varA, but varA is null
$varA is a protected variable of Class A.
Class B & C are extensions of Class A.
So $varA exists in an instance of C or B, because protected variables are accessible and assignable in the children of the class they are defined in. That's what they're for.
Since $varA exists, the __get is not triggered.
I'm not sure what you would expect to be different?

Categories