Explanation of PHP class members visibility and inheritance - php

Consider the following snippet:
Class A {
private $a = 'foo';
public function F() {
return $this->a;
}
}
Class B extends A {
private $a = 'bar';
}
echo (new B)->F();
The result is foo. Well, it's a fait accompli that php works this way. But I wonder why. If in parent's method F() declaration I use pseudo-variable $this, it refers to object context. So when I call child inherited method F() $this variable means current instance of B with private $a = 'bar', doesn't it?
Update
Thanks AbraCadaver for your reply.
One circumstance is still unclear for me: if $this variable is an object of B during call of F(), how can it access parent's private member?
Did I understand correctly that $this within parent's method implementation is something similar to:
public function F(B $obj) {
return $obj->a;
}
So interpreter checks property visibility from parent class and in case of private scope it subsitutes B $obj for A $obj

From PHP: Visibility:
Members declared
protected can be accessed only within the class itself and by
inherited and parent classes. Members declared as private may only be
accessed by the class that defines the member.
In your example, regardless of the object being of class B, class A cannot access a private property of another class.
Also, if B has a protected property, that cannot override the class A property because it is private.
Both your example and the following yield foo:
Class A {
private $a = 'foo';
public function F() {
return $this->a;
}
}
Class B extends A {
protected $a = 'bar';
public function F() {
return parent::F();
}
}
echo (new B)->F();
However, if class A is also protected then it can be overridden by class B and class A has access to the property in class B.
Yields bar:
Class A {
protected $a = 'foo';
public function F() {
return $this->a;
}
}
Class B extends A {
protected $a = 'bar';
public function F() {
return parent::F();
}
}
echo (new B)->F();

Related

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.

PHP function `get_object_vars` doesn't get private vars from inherited method

In this example I supposed that function getVars called from data would be able to return private vars names of Bdue to $this is an instance of B.
Instead of it, $this->getVars() returns an empty array.
Isn't get_object_vars called been private variables visible?
Isn't getVars a method inherited to B and called as if it was declared in it?
How can I get private variable names from a method declared in
an abstract class?
Example:
abstract class A
{
public function getVars()
{
return get_object_vars($this);
}
}
class B extends A
{
private $a;
private $b;
private $c;
public function data()
{
...
foreach($this->getVars() as $var) {
...
}
}
}
Private properties are only available to that class's methods. Try using protected properties to ensure the inherited methods have access to them.
The visibility of a property or method can be defined by prefixing the declaration with the keywords public, protected or private. Class members declared public can be accessed everywhere. Members declared protected can be accessed only within the class itself and by inherited classes. Members declared as private may only be accessed by the class that defines the member.
http://php.net/manual/en/language.oop5.visibility.php
Yes because get_object_vars is scope sensitive. If you don't wish to change the visibility of the variables then call get_object_vars directly from function data().
If you want to keep the code inheritance as it is, you'll have to change the visibility of the variables to protected.
abstract class A
{
public function getVars()
{
return get_object_vars($this);
}
}
class B extends A
{
protected $a;
protected $b;
protected $c;
public function data()
{
return $this->getVars();
}
}
$a = new B();
print_r($a->data());

Change value of a variable of the parent class in the child class

class A {
protected $a;
// SOME CODE
}
class B extends A {
// SOME CODE
}
How can i edit the protected value of the variable $a inside the B class ?
I'm trying to use parent::$a = "Some Value" but doesn't work.
protected instance properties, those which where not declared using static, can be accessed in subclasses using $this :
class A {
protected $a;
// SOME CODE
}
class B extends A {
// SOME CODE
public function edit($val) {
$this->$a = $val;
echo "a is now {$this->a}\n";
}
}
call:
$b = new B();
$b->edit('foo'); // a is now foo
Refer to the manual, especially the examples.
class B extends A {
public function foo($val)
{
$this->a = $val;
}
}
quite simple :)
Remember that
Members declared protected can be accessed only within the class
itself and by inherited and parent classes
from php manual

How can I set an object in a parent class and use it in child classes?

Here's some working code:
class A {
public $Foo;
public function GetFoo() {
$this->Foo = 'Bar';
}
}
class B extends A {
function __construct() {
$this->GetFoo();
echo $this->Foo;
}
}
$b = new B(); // Outputs "Bar"
Is there any way I can make this "prettier" (i.e. without the A::GetFoo() method)? I would've thought that wrapping the population of the $this->Foo inside a A::__construct() would work, but it doesn't.
Just to wrap it up, here's what I want: class A instantiates my DB object and that object is usable for every child class of A.
Perhaps you're overriding the parent's constructor without calling in from B?
class A {
protected $Foo = null;
public function __construct() {
$this->Foo = 'Bar';
}
}
class B extends A {
public function __construct() {
parent::__construct();
echo $this->Foo;
}
}
From the PHP manual:
"Class properties must be defined as
public, private, or protected. If
declared using var without an explicit
visibility keyword, the property will
be defined as public."
So, your class B can see $this->Foo. You don't have to call GetFoo() first. You must, however, call the parent constructor first if you need to reference $this->Foo inside of your constructor for class B.

Making a superclass object become a subclass object in PHP5

<?php
class A{
//many properties
protected $myProperty1;
protected $myProperty2;
protected $myProperty3;
public function __construct(){
$this->myProperty1='some value';
$this->myProperty2='some value';
$this->myProperty3='some value';
}
public function getProperty1(){
return $this->myProperty1;
}
public function getProperty2(){
return $this->myProperty2;
}
public function getProperty3(){
return $this->myProperty3;
}
//edited: I added some setters, meaning that the object returned from the functions may already have these properties altered
public function setProperty1($p){
$this->myProperty1=$p;
}
public function setProperty2($p){
$this->myProperty2=$p;
}
public function setProperty3($p){
$this->myProperty3=$p;
}
}
class B extends A{
private $myProperty4;
public function __construct(A $a){
$this=$a; //this line has error,it says $this cannot be re-assigned
$this->myProperty4='some value';
}
public function getProperty4(){
return $this->myProperty4;
}
}
//$a = new A();
$a = someClass::getAById(1234); //edited: $a is returned by a function (I cannot modify it)
$b= new B($a); //error
?>
I'd like to create a B's object by passing an A's object to B's constructor, as you can see, I cannot re-assign the $this variable. I am not allowed to modify class A, when there are many properties in A, it'd be tedious for me to do things like this in B's constructor:
public function __construct(A $a){
parent::__construct();
$this->myProperty1=$a->getProperty1();
$this->myProperty2=$a->getProperty2();
$this->myProperty3=$a->getProperty3();
$this->myProperty4='some value';
}
My question is that, how can I safely create an object of class B using an A's object with minimal amount of coding?
class A
{
public $property = 'Foobar';
}
class B extends A
{
public function __construct()
{
echo $this->property; // Foobar
}
}
Am I missing something? It sounds like you're trying to force OOP to do something it's not intended to do, or you're having trouble understanding inheritance.
Every public or protected method and property from class A is available in class B. Either by directly referencing it (as in my example) or by using the parent:: syntax.
EDIT
(Author clarified question)
If class A's properties are accessible, you could use something like the following to copy them down to class B
class B
{
public function __construct()
{
$a = new A(); // Or however A is instantiated
foreach(get_object_vars($a) as $key => $value)
{
$this->$key = $value;
}
}
}
Since B extends A, why not just create B to begin with? If you need to initialize some extra properties, you can over-ride the constructor like this:
class B extends A {
public function __construct(){
parent::__construct(); //calls A's constructor
$this->Bproperty='somevalue';
}
}
If that's not good enough, then you might want to look at Reflection.

Categories