I would like to have my abstract parent class have a method that would be inherited by a subclass which would allow that subclass to iterate through all of it's variables (both the variables inherited from the parent, and it's own variables).
At the moment if I implement this method in the parent, then only the parent's variables will be iterated over:
class MyObject {
private $one;
private $two;
private $three;
function assignToMembers() {
$xx = 1;
foreach($this as $key => $value) {
echo "key: ".$key."<br />";
$this->$key = $xx;
$xx++;
}
}
public function getOne() {
return $this->one;
}
public function getTwo() {
return $this->two;
}
public function getThree() {
return $this->three;
}
}
class MyObjectSubclass extends MyObject {
private $four;
private $five;
public function getFour() {
return $this->four;
}
public function getFive() {
return $this->five;
}
}
$o = new MyObjectSubclass();
$o->assignToMembers();
echo $o->getOne()." ";
echo $o->getTwo()." ";
echo $o->getThree()." ";
echo $o->getFour()." ";
echo $o->getFive()." ";
// This prints 1 2 3
On the other hand, if I put the assignToMembers function in the subclass, then only the subclass's members are iterated over.
Because I want my assignToMembers() function to be usable by a number of subclasses, I don't want to have to implement it in every one, only in the parent class, but it looks like I will have to unless it can access that class's members.
Is there any way to acheive this?
Thanks in advance.
You'll need to use protected if you want your code to work as described. Remember the roles of the access/visibility modifiers:
private - class level only access
protected - whole inheritance chain access
public - universal access
Try changing your "private" definitions to "protected" ones.
PHP Visibility:
Visibility
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 and parent classes. Members declared as private may only be
accessed by the class that defines the member.
It appears to be an issue with visibility.
In your child class, changing private to protected allows the parent to access the child's properties.
For more detailed information, see: http://us2.php.net/manual/en/language.oop5.visibility.php
Related
See the following example (PHP)
class Parent
{
protected $_property;
protected $_anotherP;
public function __construct($var)
{
$this->_property = $var;
$this->someMethod(); #Sets $_anotherP
}
protected function someMethod()
...
}
class Child extends Parent
{
protected $parent;
public function __construct($parent)
{
$this->parent = $parent;
}
private function myMethod()
{
return $this->parent->_anotherP; #Note this line
}
}
I am new to OOP and am a bit ignorant.
Here to access the parents property I am using an instance of that class, which seems wrong :S (no need of being i child then). Is there an easy way, so that i can sync the parent properties with the child properties and can directly access $this->anotherP without having to use $this->parent->anotherP ?
As your Child class is extending your Parent class, every properties and methods that are either public or protected in the Parent class will be seen by the Child class as if they were defined in the Child class -- and the other way arround.
When the Child class extends the Parent class, it can be seen as "Child is a Parent" -- which means the Child has the properties of the Parent, unless it redefines those another way.
(BTW, note that "parent" is a reserved keyword, in PHP -- which means you can't name a class with that name)
Here's a quick example of a "parent" class :
class MyParent {
protected $data;
public function __construct() {
$this->someMethodInTheParentClass();
}
protected function someMethodInTheParentClass() {
$this->data = 123456;
}
}
And it's "child" class :
class Child extends MyParent {
public function __construct() {
parent::__construct();
}
public function getData() {
return $this->data; // will return the $data property
// that's defined in the MyParent class
}
}
That can be used this way :
$a = new Child();
var_dump($a->getData());
And you'll get as output :
int 123456
Which means the $data property, defined in the MyParent class, and initialized in a method of that same MyParent class, is accessible by the Child class as if it were its own.
To make things simple : as the Child "is a" MyParent, it doesn't need to keep a pointer to... itself ;-)
This may save you a few hours of searching around.
Remember: Your Child class only inherits the properties DEFINED in the Parent class... So if you instantiate an object using Parent class and then populate it with data, then this data will NOT be available in your child class...
It's super obvious of course, but I'm guessing others may run into the same issue.
A super simple solution is not to extend anything, simply pass the $object of your parent class into your child class through a constructor. This way you have access to all the properties and methods of the object generated by parent class
Example
class child {
public parentObject;
public function __construct($parentObject) {
$this->parentObject = $parentObject;
}
}
If your $parentObject has a public property $name, then you can access it inside the child class with a function like:
public function print_name() {
echo $this->parentObject->name;
}
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());
I am using PHP.
As properties defined within the core of a class must be static, I have to create one property in the constructor to allow me to create it with a dynamic name.
Example
final class User extends Z
{
}
Abstract Class Z
{
function __constructor()
{
$x = get_called_class() . 'Id';
$this->$x = null;
}
}
If we var_dump() obj User we would have
object(User)#1 (1) {
["UserId"]=>
NULL
}
I want to set property A as a protected type.
How can I do this?
Or is there a better way to set the name of my dynamically named property?
The best you can probably do is use magic getter/setter methods and an array of properties:
<?php
abstract class Z
{
private $properties = array();
function __construct()
{
$x = get_called_class();
$this->$x = null;
}
public function __set($prop, $val)
{
$this->properties[$prop] = $val;
}
public function __get($prop)
{
return $this->properties[$prop];
}
}
class A extends Z
{
}
var_dump(new A());
Note that the property is private, child classes will have to go through the __get and __set methods.
You could also restrict dynamic properties to only be the called class name.
<?php
abstract class Z
{
private $classprop;
function __construct()
{
$x = get_called_class();
$this->$x = true;
}
public function __set($prop, $val)
{
if ($prop !== get_called_class()) {
throw new \UnexpectedValueException('Cannot Set Dynamic properties Other than Class Name');
}
$this->classprop = $val;
}
public function __get($prop)
{
if ($prop !== get_called_class()) {
throw new \UnexpectedValueException('Cannot Get Dynamic properties Other than Class Name');
}
return $this->classprop;
}
}
class A extends Z
{
}
I would encourage you to think pretty carefully about why you need dynamic properties like this.
The easiest answer would be don't - just use some generic base property, like protected $Id; and save the trouble.
If you really must have "dynamic" properties in class extensions, probably the simplest would be to declare the property in the extending class:
final class User extends Z {
protected $UserId;
}
Then your code in Z will pick out this protected property. It's psudo-dynamic, since the property name is determined by the coder, and the script only "finds" it when the constructor is run, but if your property name is already determined by something fixed at compile-time, such as the class name, there's functionally no difference.
For truly dynamic property creation, you'd have to add in a runkit, an extension that allows you to programmatically change classes, methods, properties, and functions from within the script itself. A good one seems to be this one by Demitry Zenovich. Unless you have some truly complex functions to carry out to justify the time working with it, though, it ain't going to make your life easier.
I'm a little confused about this paragraph on OO visibilty in PHP. was curious if someone could explain it to me. examples would be GREAT! my brain is not thinking clear.
http://www.php.net/manual/en/language.oop5.visibility.php
The first paragraph reads
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 and parent
classes. Members declared as private
may only be accessed by the class that
defines the member.
how can a parent class access a childs class member?
That's how:
class A {
public function test() {
$b = new B;
echo $b->foo;
}
}
class B extends A {
protected $foo = 'bar';
}
$a = new A;
$a->test();
PHP is an interpreted language. Properties are resolved at runtime, not at the compiling stage. And access modifiers are just checked when a property is accessed.
It makes no difference if you ad-hoc inject a new (undeclared) property so it becomes public, or if you declare a protected property in an inherited class.
The private really only affects the accessibility from the outside. The ->name resolving at runtime works regardless of that. And the PHP runtime simply doesn't prope if the property declaration was made for the current object instances class. (Unlike for private declarations.)
public scope: property (method, variable etc) can be accessed from any class in any file.
class Example {
public $foo;
}
$example = new Example;
$example->foo = 3; // everything OK
private scope: property can only be accessed only by same class.
class Example {
private $foo;
}
class Child_Class extends Example {
public function some_method()
{
parent::foo = 3; // raises error
}
}
protected scope: property can only be accessed by same class or by other classes that extend it.
class Example {
protected $foo;
}
class Child_Class extends Example {
public function some_method()
{
parent::foo = 3; // this is OK
}
}
It all has to do with a technique named encapsulation, in which you must not allow a class member's state or behavior to be changed outside the class. http://en.wikipedia.org/wiki/Encapsulation_(object-oriented_programming)
Protected is a type of visibility which makes properties and methods declared protected available in the child classes of the declared class.
class Parent {
public $name = 'MyName';
protected $age = 20;
private $school = 'MySchool';
}
class Child extends Parent {
public function __construct() {
echo $this -> name; // valid as public
echo $this -> age; // valid as protected
echo $this -> school; // invalid as private
}
}
There you understand protected is something that used in inheritance.
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