Inheritance and function calls parent and sub-class - php

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.

Related

PHP defining private abstract function/method

Went over a thing like this and I don't know
abstract class Foo {
abstract private function test();
}
Is this a nonsense or NOT?
If not please explain why.
if you speak about private range inside you abstract class, no it is not a nonsence
Since an abstract class can contain functionality (as opposed to an interface) it can have private variables or methods.
I will give you this link with a great answer (even it is in java, it is the same with php) Why is there a private access modifier in an abstract class in Java, even though we cannot create an instance of an abstract class?
Abstract methods cannot be private, because by definition they must be implemented by a derived class. If you don't want it to be public, it needs to be protected, which means that it can be seen by derived classes, but nobody else.
The PHP manual on abstract classes shows you examples of using protected in this way.
http://php.net/manual/en/language.oop5.abstract.php
It makes sense if you want to make that method inaccessible further down in the inheritance chain, e.g. grandchildren of that abstract class. For example:
abstract class Foo {
abstract private function test();
}
class FooChild extends Foo {
private function test()
{
// Here you implement the body of the method
}
public function bar()
{
$this->test(); // This will work
// Do something else
}
}
class FooGrandChild extends FooChild {
}
$grandchild = new FooGrandChild();
$grandchild->test(); // This will throw an exception

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.

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?

Class inheritance - Calling properties and/or methods not in the parent class

I'm trying to understand class inheritance.
Suppose I have the following code (PHP):
class A {
public function fire() {
echo "Fire!";
}
}
class B extends A {
public function water() {
echo "Water!";
}
}
class C extends B {
public function lightning() {
echo "Lightning!";
}
}
$cObject = new C();
$cObject->fire();
My questions are
Even though the fire() method is not defined in class C nor class B, $cObject->fire() works. Does class C inherit not only class B's methods, but class A's methods? I'm trying to find out how many levels deep inheritance will go.
Is there a term for calling a property or method that does not exist in the current object instance, but this property or method exists in a parent or ancestor class? EDIT: In other words, fire() is not defined in class C, but $cObject can still call fire(). Is there any particular term/jargon for this concept? (Or is it just part of the definition of "class inheritance")
I'm trying to find out how many levels deep inheritance will go.
infinetely, if you want. no limits
Is there a term for calling a property or method that does not exist in the current object instance, but this property or method exists in a parent or ancestor class?
For class variables: no.
For class methods: yes. declare them as private:
class A {
private function test() {
echo 'test';
}
}
class B extends A {
public function __construct() {
$this->test();
}
}
$b = new B();
Output:
Fatal error: Call to private method A::test() from context 'B' in /home/thorsten/a.php on line 14
1) Class 'B' is an 'A'. Class 'C' is a 'B', therefor, 'C' is an 'A'. Everything that 'B' has rights and privileges to in 'A', 'C' has as well. C++ has a concept of private inheritance that gets a little funky here, but that's the general idea. As said in the other answer, inheritance will go as far as the chain is defined.
2) I think you meant to ask "What is a function called that is not defined in derived class, but instead in the base class. This type of function is called a virtual function. From what I understand, every class function in PHP is a virtual function and can be overridden (reimplemented in a derived class) unless it is declared as final.

Accessing child variables from the super class without instanciation

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 ...

Categories