Inherited function doesn't access private var of the child class - php

I need some help. This code doesn't mean to do anything I was just trying to learn how these inheriting functions work.
So both parents and child class have $wheels variable and set to private (It doesn't make sense but I was just playing around with the code).
A method is used to print the number of wheels of the Instance. This method is not overridden in the child class. Parent and child objects were created and wheel_details() were invoked using each object.
However, when invoked using the child object, the method doesn't use the child object's private var. Instead it prints the parent object's var.
How and why do you think it accesses the parent class's private var instead of its own private var.
Appreciate an insight on this. TIA
class Bicycle {
private $wheels = 2;
public function wheel_details(){
return " It has {$this->wheels} wheels. Invoked by ". get_class($this) ;
}
}
class Unicycle extends Bicycle {
private $wheels = 1;
}
$b1 = new Bicycle;
$b2 = new Unicycle;
echo "Bicycle1 wheels ". $b1->wheel_details(). " <br />";
echo "Bicycle2 wheels ". $b2->wheel_details(). " <br />";
/*Output
=======
Bicycle1 wheels It has 2 wheels. Invoked by Bicycle
Bicycle2 wheels It has 2 wheels. Invoked by Unicycle
*/

This is by design:
Members declared as private may only be accessed by the class that defines the member.
If you want to override the value from a child class, use protected instead.

Related

How do you keep track where an inherited method comes from

Considering this simple example of classes:
// father.php
class father {
public function wallet () {}
}
// mother.php
class mother extends father { }
// daughter.php
class daughter extends mother {
public function shop {
$this->wallet();
}
}
Is there a convention/coding practice that tells you quickly that wallet() comes from class father?
This isn't a big deal but when reviewing old code (without an IDE) it's nice to know quickly where inherited methods come from.
Though seemingly trivial, one has to loop over sequence of parent's classes:
$seekMethod = 'wallet';
$stack = [];
foreach(class_parents('daughter') as $parent){
foreach((new ReflectionClass($parent))->getMethods() as $method){
if($seekMethod == $method->name){
$stack[] = "{$method->class}::{$method->name}() in {$parent}";
echo "Found ".end($stack);
}
}
}
echo "{$seekMethod} is defined in ".end($stack);
Will output something like:
Found father::wallet() in mother
Found father::wallet() in father
wallet is defined in father::wallet() in father
Or simpler, without respecting inheritance:
foreach((new ReflectionClass('daughter'))->getMethods() as $method){
if($seekMethod == $method->name){
echo "Found {$method->class}::{$method->name}";
}
}
Will output e.g.
Found father::wallet
Inheritance isn't the easiest to follow without an IDE (or a lot of documentation).
PHPDoc does have the #see tag which you could use as:
/**
* #see father::wallet() For logic pertaining to wallet retrieval
*/
public function shop {
$this->wallet();
}
Beyond that, you want to make sure your inheritance makes sense. I'm sure this was just a quick example, but I don't see any reason why a daughter would ever extend a father.
A daughter could extend a Child, and in the Child, you could have the logic pertaining to pulling the wallet from a parent (or father).

PHP: Why do Inherited Methods of Child Class access Parent's Private Properties?

What a curious twist in PHP's property and method inheritance. See the following example:
class A {
private $foo = 'hello';
function get() {
return $this->foo;
}
function set($val) {
$this->foo = $val;
}
}
class B extends A {
private $foo = 'world';
function get() { // try inheriting this
return $this->foo;
}
function set($val) { // try inheriting this
$this->foo = $val;
}
}
Now let's see how that echoes out if we inherit or define methods:
$b = new B();
/* If B defines getter: */
echo $b->get(); // 'world'
/* If B inherits getter: */
echo $b->get(); // 'hello'
// Enter Setter!
$b->set('cosmos');
/* If B defines setter & inherits getter: */
echo $b->get(); // 'hello'
/* If B inherits setter & defines getter: */
echo $b->get(); // 'world'
/* If B defines or inherits both: */
echo $b->get(); // 'cosmos'
So: When class B defines the getter, it returns its own private $foo ( = "world"). However if I remove the getter from class B, and class B inherits the very same method from class A, it returns instead the private $foo property from the parent class A (= "hello") instead. Likewise with setters.
I was expecting inherited methods to access the properties of the instantiated class at all times, with no reference to their ancestors' private properties. They are private for a reason, no? Private with side-effects! If I change the prop visibility to public or protected, the expected properties "world" and "cosmos" from class B are returned, whether methods are defined or inherited.
Here are object dumps for each of the above cases:
var_dump($b);
/* If B defines getter (Prop get from B): */
["foo":"B":private] · string(5) "world"
["foo":"A":private] · string(5) "hello"
/* If B inherits getter: (Prop get from A) */
["foo":"B":private] · string(5) "world"
["foo":"A":private] · string(5) "hello"
// Enter Setter!
$b->set('cosmos');
/* If B defines setter & inherits getter
* Prop set to B & get from A */
["foo":"B":private] · string(6) "cosmos"
["foo":"A":private] · string(5) "hello"
/* If B defines getter & inherits setter
* :: Prop set to A & get from B */
["foo":"B":private] · string(5) "world"
["foo":"A":private] · string(6) "cosmos"
/* If B defines both:
* :: Prop set to B & get from B */
["foo":"B":private] · string(6) "cosmos"
["foo":"A":private] · string(5) "hello"
/* If B inherits both:
* :: Prop set to A & get from A: */
["foo":"B":private] · string(5) "world"
["foo":"A":private] · string(6) "cosmos"
Can someone explain to me the logic in what's going on? Are inherited property-access methods bound to the private properties of the original method-defining parent class? I'd rather not copy-paste the same method into each child class that has private properties with a matching name.
Excuse me if the illustrations above go on ad nauseam. Had to spell this out for my own sanity huh -- unexpected behavior, unless I'm missing something obvious. (N.B. Having constructors or invoking parent::__construct() in the child class constructor has no impact on this behavior.)
Add: Now one step further. If I declare the getters protected, and create a public method in class B for getting variables. Like so:
class B {...
public function getpro_direct() {
return $this->foo;
}
public function getpro_getter() {
return $this->get();
}
...}
echo $b->getpro_direct(); // "world" (from B)
echo $b->getpro_getter(); // "hello" (from A)
And if I inherit these two methods from A instead, I get "hello" on both counts. But if I define a get() in B, I get "hello" and "world" respectively. Hello world hello, cosmos calling. I need some juice.
Edit for those of you wondering why I'm at this. The short background story: I'm working on a class hierarchy that grows in more depth in (array) properties, with each child class being a less abstract version down the same vector. (Spare you the examples.) I'm working out the smartest way to merge the child's extended properties with each consecutive parent's basis.
Private declaration was so far the only way to prevent the child class from overwriting the parent's properties, as I could have the properties of both simultaneously available via using the parent getter. That however mucks up the method inheritance, as illustrated here. I'd like to get this done as automagically as possible; preferably with a single clone_parent() method that's inherited and run in each child's constructor. I'd rather avoid spelling out separate cloners for each parent-child extension hop. (I've searched and read around a bunch here, yet to find a satisfactory solution.)
Edit2: Other approaches pending, on my actual concern (as above) that led to this experiment. To keep things simple, I'll just ditch the overlapping declaration in the child's properties and call an extend_props method that adds atop the props inherited from the arent. (Alas I hoped to have each extending class's extras shown pretty up atop, instead of lurking down below inside a method!)
Private properties are not accessible outside his own class.
If you're extending a class, they aren't accessible outside too. The reason that you "see the private property of the parent" is that you've defined a getter in the parent. This getter has access to the private property, because he is in the same class. It's not strange.
I suggest you to read more about private, protected and public.

Setting protected variable value in child class and accessing value in parent

I'm not sure if this is even possible but here goes. I want to set the value of a protected variable from within a child class and then access that value from the parent class. This is what I have tried:
class A {
protected $a;
public function __construct() {
new B;
echo "Parent Value: {$this->a}";
}
protected function setter($value) {
$this->a = $value;
}
}
class B extends A {
public function __construct() {
$this->setter('set value');
echo "Child Value: {$this->a}<br />";
}
}
new A;
I'm expecting the output for the above code to be:
Child Value: set value
Parent Value: set value
However I get the following instead:
Child Value: set value
Parent Value:
Is it possible to set the value of a protected variable from within a child class and then access that value in the parent class? If not how would I accomplish this?
You can set the value and access it from the child class without any problems - you are actually doing that when you generate your B-class object in the A-class constructor - but the problem with your code is that you are generating a parent object and in the constructor of that parent object you generate a new object of the child class.
So what is happening is:
You generate an A object, the constructor of the A class runs;
In the constructor you generate a B object. This is a new object, unrelated to your current A object;
The constructor of the B object you set the value and echo it (basically answering your own question), the first line of your output is as expected;
Continuing in the constructor of the A object, you discard the generated B-class object and echo the value of $this->a but that value is not set for that object, so you get nothing.
I am kind of confused why you would want to construct a child object in the constructor of the parent. Normally I would construct a B object and in the constructor of that object, first call the parent constructor before doing B-specific stuff.

Checking if variable exists for child class

I'm creating global setters and getters for my parent class since I don't want to create them for each child class variable (but I will occasionally overwrite the parent global setter / getter).
I'm using __call with it and I'm parsing the method name like this:
if (strtolower(substr($method, 0, 3)) == "set") {
$variable = strtolower(substr($method, 3));
}
The question is how can I check if the $variable is set for the child class (the one that is extending the main one);
If I do:
if ($this->$variable)
I suppose it first check if it exists on the child class and then it checks if it exists on the main class. I want it only to check the child class, is this possible to do?
I know there's parent:: but is there an equivalent for child?
EDIT:
People are not understanding what I'm asking.
I know how to check if the property exists. What I want to know is how to check if the property exists for the CHILD class, not for the MAIN class.
(class CHILD extends MAIN)
In common case there's isset() function, but is will not fit this case. Use property_exists() instead:
class Foo
{
public $pub = null;
}
$obj = new Foo();
var_dump(isset($obj->pub), property_exists('Foo', 'pub')); //false, true
-that's because if proprty exists, but is null, isset() will return false - and you'll not be able to differ the case, when it does not exist.
If it's about dynamic properties - then you should pass object and not class name to property_exists() since property may absent in class and then dynamically added to object.
Now, if we're saying about which class is declaring property, you can use Reflection in PHP, like this:
class Foo
{
public $pub = null;
}
class Bar extends Foo
{
}
$obj = new Bar();
$ref = new ReflectionObject($obj);
var_dump($ref->getProperty('pub')->getDeclaringClass()->getName() == 'Bar');//false
var_dump($ref->getProperty('pub')->getDeclaringClass()->getName() == 'Foo');//true
Why don't you make use of isset ??
if (isset($this->$variable))
This works for me:
if(property_exists($get_class($this),$variable)){}

Are classes and objects the same thing in PHP?

Just starting out with OOP in PHP and in general. From what I have been reading so far the two seem to be synonyms. Is this the case, and if not, practically speaking when people refer to objects and classes do they generally use the terms interchangeably?
Typically one would refer to an object as an instance of a class.
So you have some class Employee.
class Employee {
var $name;
function get_name ( ) { return $this->name; }
function set_name ($new_name) { $this->name = $new_name; }
}
And you declare an instance of it like:
$assistant = new Employee();
Employee is a class. $assistant is an object, that is an instance of the Employee class.
So to answer your question - a class is not an object. You create an object when you instantiate a class.
objects and classes do they generally use the terms interchangeably?
No. As in other OOP languages, classes are like the blueprints for something, say a house. Objects are the actual house after it's built. Very different things indeed.
// blueprint
class House
{
public $color;
public function __construct($color = 'red')
{
$this->color = $color;
}
}
// make red house
$redHouse = new House();
// make blue house
$blueHouse = new House('blue');
// Now we have two different houses (objects) made from the same blueprint (class)
They're certainly not synonymous, and if you've been reading that, it's time to change the book! :-)
Classes are types, while objects are instances.
A simple example is an integer. "Integer" denotes the type, but an integer $x is an instance of that type. In PHP there isn't a strong type system, so this may not be entirely apparent, but I hope you get the idea. Similarly, array is a type, but $v = array(); creates an instance (called $v) of array type.
With classes, you cannot just say $y = MyClass(); as you do with arrays, instead, you have to use new: $y = new MyClass();.
A class is a definition of an object. An object is an instance of a class. For example:
class Parser {
public function parse() {}
}
...is a class. You might say "The Parser class can be used to parse text."
$p = new Parser;
Now, $p is an object. It is an instance of the Parser class.
This is particularly important with the static keyword. Static methods and members belong to classes, not objects.
class Parser {
public static $type;
public $text;
}
$p1 = new Parser;
$p2 = new Parser;
$p1::$type = 'php';
$p1->text = 'sometext';
$p2->text = 'someothertext';
echo $p2::$type; //echos "php"
echo $p1->text; //echos "sometext"
You can remove the in php from your question and it is still the same thing.
A class defines an Object for example
class Person {
}
is a class that defines an person object.
The distinction get more important when you start creating class methods and object methods
class Person {
function hair_color(color) {
hair_color = color;
}
}
is an object method in php you could do something like this
austin = new Person()
austin -> hair_color("brown")
now you can have something like
class Person {
total = 0;
static function total_in_class() {
total++;
}
}
now that is an class method it affects all objects of the same class
that way
austin = new Person();
austin -> total_in_class
tom = new Person();
echo tom->total
Now if my php isn't that rusty then it should echo 1. That is because all objects in the class are affected
In ruby it would look as follows
class Person
def hair_color(color)
hair_color = color;
end
def self.total_in_class()
total+=1
end
end
Similar and same concepts apply

Categories