Merging properties of parent and child classes - php

I am trying to merge a property in an abstract parent class with the same property in a child class. The code looks sort of like this (except in my implementation, the property in question is an array, not an integer):
abstract class A {
public $foo = 1;
function __construct() {
echo parent::$foo + $this->foo; # parent::$foo NOT correct
}
}
class B extends A {
public $foo = 2;
}
$obj = new B(); # Ideally should output 3
Now I realize that parent::$foo in the constructor will not work as intended here, but how does one go about merging the property values without hardcoding the value into the constructor or creating an additional property in the parent class?

In the constructor of your parent class, do something like this:
<?php
abstract class ParentClass {
protected $foo = array(
'bar' => 'Parent Value',
'baz' => 'Some Other Value',
);
public function __construct( ) {
$parent_vars = get_class_vars(__CLASS__);
$this->foo = array_merge($parent_vars['foo'], $this->foo);
}
public function put_foo( ) {
print_r($this->foo);
}
}
class ChildClass extends ParentClass {
protected $foo = array(
'bar' => 'Child Value',
);
}
$Instance = new ChildClass( );
$Instance->put_foo( );
// echos Array ( [bar] => Child Value [baz] => Some Other Value )
Basically, the magic comes from the get_class_vars( ) function, which will return the properties that were set in that particular class, regardless of values set in child classes.
If you want to get the ParentClass values with that function, you can do either of the following from within the ParentClass itself: get_class_vars(__CLASS__) or get_class_vars(get_class( ))
If you want to get the ChildClass values, you can do the following from within either the ParentClass, or the ChildClass: get_class_vars(get_class($this)) although this is the same as just accessing $this->var_name (obviously, this depends on variable scope).

You can't directly do that. You'd need to define it in the constructor of B, since B->$foo would overwrite A's at compile time (and hence A->$foo would be lost):
abstract class A {
public $foo = 1;
function __construct() {
echo $this->foo;
}
}
class B extends A {
public function __construct() {
$this->foo += 2;
}
}
Now, there are ways around that, but they involve Reflection and will be dirty. Don't do that. Just increment it in the constructor and be done...

You can't. The best option you have is to have another property. I know that you already know this, but that's the best solution.
<?php
class A {
protected $_foo = 2;
}
class B extends A {
protected $foo = 3;
function bar( ) {
return $this->_foo + $this->foo;
}
}
That's your best bet.

Related

Access parent and child variables in method defined in parent - PHP

I have a child object that inherits from a parent. Both have a static variable which has a different value in each object; I want to add that variable from both parent and child to an array when I instantiate the child. To save duplicating code, I've written a method (addFoo) in the parent which is called from both the parent and the child constructors. However, I can't seem to find a way to distinguish between the calls when the parent constructor is called from the child constructor (as you can see below, the output from the method is the same in both cases whether using $this, self or static).
class A {
public static $foo = 'foo';
public $thisvars = array();
public $selfvars = array();
public $staticvars = array();
public function __construct() {
$this->addFoo();
}
public function addFoo() {
$this->selfvars[] = self::$foo;
$this->staticvars[] = static::$foo;
$this->thisvars[] = $this::$foo;
}
}
class B extends A {
public static $foo = 'bar';
public function __construct() {
parent::__construct();
$this->addFoo();
}
}
$b = new B;
print_r($b->selfvars);
print_r($b->staticvars);
print_r($b->thisvars);
Output:
Array
(
[0] => foo
[1] => foo
)
Array
(
[0] => bar
[1] => bar
)
Array
(
[0] => bar
[1] => bar
)
I can workaround this by passing the calling class through to the addFoo function (see below), but is there a better (correct?) way?
class C {
public static $foo = 'foo';
public $vars = array();
public function __construct() {
$this->addFoo(__CLASS__);
}
public function addFoo($class) {
$this->vars[] = $class::$foo;
}
}
class D extends C {
public static $foo = 'bar';
public function __construct() {
parent::__construct();
$this->addFoo(__CLASS__);
}
}
$d = new D;
print_r($d->vars);
Output:
Array
(
[0] => foo
[1] => bar
)
Demo on 3v4l.org
Instead of having addFoo be called by every sub-constructor, one way would be to have a single addFoos method in the base class that is called by the base constructor, that would append all the $foo values starting from the late static binding class:
class A
{
public static $foo = 'foo';
public $vars = [];
public function __construct()
{
$this->addFoos();
}
private function addFoos()
{
$class = static::class;
do {
$this->vars[] = $class::$foo;
} while ($class = get_parent_class($class));
}
}
class B extends A
{
public static $foo = 'bar';
}
class C extends B
{
public static $foo = 'baz';
}
$a = new A;
print_r($a->vars); // ['foo']
$b = new B;
print_r($b->vars); // ['bar', 'foo']
$c = new C;
print_r($c->vars); // ['baz', 'bar', 'foo']
That method is marked private as it's not supposed to be extended in this scenario (nor called from the outside).
Demo
I would alternatively consider another, more straightforward approach:
class A
{
public static $foo = 'foo';
public function getVars()
{
return [self::$foo];
}
}
class B extends A
{
public static $foo = 'bar';
public function getVars()
{
return array_merge(parent::getVars(), [self::$foo]);
}
}
class C extends B
{
public static $foo = 'baz';
public function getVars()
{
return array_merge(parent::getVars(), [self::$foo]);
}
}
$a = new A;
print_r($a->getVars()); // ['foo']
$b = new B;
print_r($b->getVars()); // ['foo', 'bar']
$c = new C;
print_r($c->getVars()); // ['foo', 'bar', 'baz']
You do have to redefine getVars on each subclass in this case, but after all, it makes sense for each class to decide which variables should be exposed. Your code becomes a bit less obscure / easier to maintain in the process.
And if a class doesn't need/want to "contribute", you can simply omit both the static property and the getVars extension for that class.
Demo
Notes:
you can easily cache the variables into a $vars property inside A if needed,
order is swapped from the other answer but you can obviously swap the array_merge if needed,
in both this sample and the one from the other answer, I'm not sure if the $foo static properties need to be public, but I've left them like they were in your question.

public/protected class properties don't override private properties on parent classes?

Declare a private property on a Parent class, and then redeclare that property as public or protected on a Child class.
When you create an instance of the Child class, and invoke a method that is inherited from the Parent class. The property on the Parent class is used, and not the property on the Child class.
This is not the case if the initial declaration of the property on the Parent class is public or protected.
Could someone explain to me why this is?
<?php
class P {
private $foo = 'bar';
public function e()
{
echo get_class($this);
echo "\n";
echo $this->foo;
echo "\n";
}
}
class C extends P
{
protected $foo = 'baz';
}
$parent = new P();
$child = new C();
$parent->e();
$child->e();
Output:
P
bar
C
bar
Expected Output:
P
bar
C
baz
Private properties are, as the name implies, private. This means they only be accessed from within the class. As others have mentioned in the comments, this question offers a very good in depth explanation of variable scope in PHP, so by all means go check it out, it's an interesting read.
In your specific however, you seem to be concerned about renaming/overloading variables in a child class. More specifically, we're looking at what happens when a parent and child class happen to both have a property of the same name, and the parent class has a function which return that property.
class A {
private $foo = 'bar';
public function getFoo() {
return $this->foo;
}
}
class B extends A {
protected $foo = 'something something';
}
$b = new B;
echo $b->getFoo();
In the example above, the output would be bar, and that's actually the expected behavior. Since the function getFoo is not overwritten in the child class, PHP executes the function in the parent class. When it gets there, $this refers to A and therefore prints the value of $foo as it is defined in A. It's interesting to note that in this specific example, the scope of B::foo does not matter. In fact, it could omitted entirely and the code would still run perfectly fine.
We can experiment with different function scopes and see what happens:
class A {
private $foo = 'bar';
public function getFoo() {
return $this->foo;
}
private function getCapitalizedFoo() {
return strtoupper($this->foo);
}
protected function getDoubleFoo() {
return $this->foo . $this->foo;
}
}
class B extends A {
protected $foo = 'something something';
public function getParentDoubleFoo() {
return parent::getDoubleFoo();
}
}
$b = new B;
echo $b->getFoo().PHP_EOL; // Output: bar
echo $b->getParentDoubleFoo(); // Output: barbar
echo $b->getDoubleFoo(); // Output: Uncaught Error: Call to protected method ...
echo $b->getCapitalizedFoo(); // Output: Uncaught Error: Call to private method ...
Now, the question remains: How can you access private members from a parent class?
If you have read on the subject, you probably know that, unless completely necessary, your object's properties should be private so as to encapsulate its logic and data as much as possible. Knowing that, the best to allow a child class to access and modify its parent's class properties is by creating accessors and mutators for them.
class A {
private $foo = 'foo';
private $bar = 'bar';
public function setFoo($foo) {
$this->foo = $foo;
}
public function getFoo() {
return $this->foo;
}
protected function setBar($bar) {
$this->bar = $bar;
}
protected function getBar() {
return $this->bar;
}
}
class B extends A {
public function __construct() {
parent::setFoo('more foo');
parent::setBar('more bar');
}
public function getCapitalizedFoo() {
return strtoupper(parent::getFoo());
}
public function getCapitalizedBar() {
return strtoupper(parent::getBar());
}
}
$b = new B;
echo $b->getCapitalizedFoo(); // Output: MORE FOO
echo strtoupper($b->getFoo()); // Output: MORE FOO
echo $b->getCapitalizedBar(); // Output: MORE BAR
echo strtoupper($b->getBar()); // Output: Uncaught Error: Call to protected method ...
By creating public functions to access and modify the parent class' properties you allow the child class to overwrite them and perform logic of its own without having to duplicate the variable. However this also means that any instance of B can potentially alter the values defined in A. In order to mitigate this, you can create protected function that will allow B to internally access and consume the parent class attributes, but the code that consumes B will not be able to do the same.

Changing variable set by parent class without modifying the constructor

I have been searching for this since a couple of days but found no solution.
Here's my code:
// Main class
class My_Parent {
private $foo = '';
// The constructor is set. Now all extended classes will get it.
function __construct() {
var_dump( $foo );
}
function set_val( $value ) {
$this->foo = $value;
}
}
// Extended class
class My_Child extends My_Parent {
// Here's the problem. I've modified the constructor
function __construct() {
parent::set_val( 'bar' );
parent::__construct(); // I don't want to call the parent costructor again
}
}
new My_Child();
This just work fine but not as I expect. I don't want to modify the constructor so I need to call it again from the parent. Which looks weird. I'm going to make an extendable framework for my projects. So, this thing is annoying.
I do want something like this:
class My_Child extends My_Parent {
// Just set the value somehow. do not modify the constructor
$this::set_val( 'bar' );
}
new My_Child();
So that, I don't have to call the constructor again. But the code above throws a syntax error.
Any hope about this?
Just found a tricky solution.
First I've set up an empty function and called it in the constructor of parent class. Then I modified the variable through that function in extended class. The code looks like this:
// Main class
class My_Parent {
private $foo = '';
// The constructor is set. Now all extended classes will get it.
function __construct() {
// We open the portal so that the value can change
$this->portal();
// Then we use the value as we want
var_dump( $foo );
}
function set_val( $value ) {
$this->foo = $value;
}
// This function will play the role of constructor of extended classes
function portal() {
}
}
// Extended class
class My_Child extends My_Parent {
// We just use portal to set the value. Constructor is still untouched!
function portal() {
parent::set_val( 'bar' );
}
}
new My_Child();
This is working perfectly as I wanted. Everything is explained in comments.
Maybe you're over-thinking this. If you want to initialize the property with a constant value, you can simply declare it protected and override it in the subclass:
class MyParent {
protected $foo = 'bar';
// ...
public function getFoo() {
return $this->foo;
}
}
class MyChild extends MyParent {
protected $foo = 'baz';
}
echo (new MyParent())->getFoo(); // "bar"
echo (new MyChild())->getFoo(); // "baz"

How to force parent class to keep value of its protected property?

I have two classes Foo and Bar that Bar extends Foo as below:
class Foo {
protected
$options = array(),
$defaults = array(1, 2);
public function __construct($options){
array_push($this->options, $this->defaults);
}
}
class Bar extends Foo {
protected $defaults = array(3, 4);
public function print(){
print_r($this->$options);
}
}
$bar = new Bar();
$bar->print();
i thought that result should be array(1,2,3,4) but is array(3,4).
how to solve that ?
edit
i don't want Bar class to have constructor because i'm just implementer of superclass and don't know what really will happen in child class.
There are a couple of solutions, the simplest would be a second variable to be used as an extended defaults, then merge the arrays.
class Foo {
protected
$options = array(),
$original_defaults = array(1, 2),
$extended_defaults = array();
public function __construct($options){
array_merge($this->extended_defaults, $this->original_defaults);
array_push($this->options, $this->original_defaults);
}
}
class Bar extends Foo {
protected $extended_defaults = array(3, 4);
public function print(){
print_r($this->$options);
}
}
$bar = new Bar();
$bar->print();
Why would it combine your arrays?
You set $defaults to (1,2) and then to (3,4) - nowhere are you concatenating them.
Your constructor adds (1,2) onto $options. That's all it does.
Your print method outputs $defaults which at this point would be (3,4) because you initialise them as a protected var.
If you don't want those values to be overridden then use private instead of protected. This will prevent subclasses from overriding those values.
First- You cannot have a method named print. print is a language construct and cannot be overridden.
Second- you should make the default values for a class private, and override them in child classes. Then you can combine them in the parent when you call the constructor. It's not 100% clear what you're trying to accomplish, but the following will merge the sub-class' default options with the superclass':
Updated to remove constructor
abstract class Foo {
protected $options = array();
private $defaults = array(1, 2);
// Implementations of this class MUST define this method
abstract function overrideDefaults();
public function __construct($options = array()){
// Merge any incoming options with the default options
$this->options = array_merge($this->defaults, $options);
}
// Concrete children can use this method to modify the current options by
// passing in their own defaults.
protected function modifyDefaults( $defaults ) {
$this->options= array_merge( $this->defaults, $defaults );
}
public function printOps(){
print_r($this->options);
}
}
class Bar extends Foo {
private $defaults = array(3, 4);
public function overrideDefaults() {
parent::modifyDefaults( $this->defaults );
}
}
$bar = new Bar();
$bar->overrideDefaults();
$bar->printOps();
Notice I also moved the now printOps method to the superclass. Output:
Array ( [0] => 1 [1] => 2 [2] => 3 [3] => 4 )
"I just want each child class could have it's default values".
You want to have specific data for each class.
You can use "static fields", make class act as a variable, by itself. Im not very fan of "static members", but I think, it applies to your "use case".
class Foo {
private
// (1) "private" only accessed by the class itself,
// neither external code, or subclasses,
// (2) "static", specific to the class,
static $defaults = array(1, 2);
protected
// want to be accessed only by class & subclasses
$options = array();
// when using "static fields" in constructor,
// you need to override constructor
public function __construct($options){
array_push($this->options, Foo::$defaults);
}
// ops, "print" is reserved identifier
// public function print(){
public function display_options() {
print_r($this->$options);
}
public function display_defaultoptions() {
// in order to acccess "static fields",
// you use the class id, followed by double colon,
// not "$this->*"
print_r(Foo::$defaults);
}
} // class Foo
class Bar extends Foo {
private
// (1) "private" only accessed by the class itself,
// neither external code, or subclasses,
// (2) "static", specific to the class,
static $defaults = array(1, 2);
// when using "static fields" in constructor,
// you need to override constructor
public function __construct($options){
array_push($this->options, Bar::$defaults);
}
public function display_defaultoptions() {
// in order to acccess "static fields",
// you use the class id, followed by double colon
// not "$this->*"
print_r(Bar::$defaults);
}
} // class Bar
$bar = new Bar();
$bar->print();
Cheers

PHP: How to call private values of parent construct in child construct?

I want to be able to set a private attribute's value in the parent constructor, and call the value in a child's constructor or method.
For example:
<?php
abstract class MainClass
{
private $prop_1;
private $prop_2;
function __construct()
{
$this->prop_2 = 'this is the "prop_2" property';
}
}
class SubClass extends MainClass
{
function __construct()
{
parent::__construct();
$this->prop_1 = 'this is the "prop_1" property';
}
public function GetBothProperties()
{
return array($this->prop_1, $this->prop_2);
}
}
$subclass = new SubClass();
print_r($subclass->GetBothProperties());
?>
Output:
Array
(
[0] => this is the "prop_1" property
[1] =>
)
However, if I change prop_2 to protected, the output will be:
Array
(
[0] => this is the "prop_1" property
[1] => this is the "prop_2" property
)
I have basic knowledge of OO and php, but I can't figure out what is preventing prop_2 from being called (or shown?) when it's private; it can't be a private/public/protected issue, since 'prop_1' is private and able to be called and shown... right?
Is it an issue of assigning the values in the child class vs parent class?
I would appreciate help in understanding why.
Thank you.
Private properties of parent class can not be accessed in Child class and vice versa.
You can do like this
abstract class MainClass
{
private $prop_1;
private $prop_2;
function __construct()
{
$this->prop_2 = 'this is the "prop_2" property';
}
protected function set($name, $value)
{
$this->$name = $value;
}
protected function get($name)
{
return $this->$name;
}
}
class SubClass extends MainClass
{
function __construct()
{
parent::__construct();
$this->set('prop_1','this is the "prop_1" property');
}
public function GetBothProperties()
{
return array($this->get('prop_1'), $this->get('prop_2'));
}
}
If you want to access the parent's properties from the child class, you must make the parent's properties protected NOT private. This way they are still inaccessible externally.
You can't override the parent's private properties visibility in the child class in the way you are trying to.
As others have noted, you'd need to change the parent's properties to protected. However, the other way is by implementing a get method for your parent class, which allows you access to the property, or implementing a set method if you want the ability to over-ride it.
So, in your parent class, you'd declare:
protected function setProp1( $val ) {
$this->prop_1 = $val;
}
protected function getProp1() {
return $this->prop_1;
}
Then, in your child class, you can access $this->setProp1("someval"); and $val = $this->getProp1(), respectively.
There is a simple trick you an use with lambdas, which I found here: https://www.reddit.com/r/PHP/comments/32x01v/access_private_properties_and_methods_in_php_7/
basically you use a lambda and bind it to the instance and then you can access it's private methods and properties
Info on the lambda call: https://www.php.net/manual/en/closure.call.php

Categories