Ok, I know there are similar questions, but they don't quite answer my question. I have a rather long class and decided to break it up. The bulk of it is a set of functions determining whether or not to change a certain value (both in the parent class and the database). The issue I'm having is inheritance and I'm clearly not understanding.
The problem is that the properties in the parent class aren't determined until after certain functions have executed. I need those properties in the child class in order to update the properties in the parent class once the child has finished doing its thing. Because of this, a simple "new Child" won't work (or will it?), because the properties haven't been determined in the new parent created.
I'm trying NOT to instantiate another instance of the parent class in order to repopulate the properties again. But at the same time, I don't need to always instantiate the child class when the parent is instantiated.
Here's what I'm trying to do...
class parentClass
{
public $value1;
public $value2;
public $value3;
public function getValues()
{
$this->curValues();
$chi = new childClass();
$chi->updValues();
echo var_dump($this->value1, $this->value2, $this->value3);
}
public function curValues()
{
$this->value1 = 'first value';
$this->value2 = 'second value';
}
}
class childClass extends parentClass
{
public function updValues()
{
if (2 > 1) {
$this->value2 = 'blue value';
$this->value3 = 'third value';
}
}
}
$hmm = new ParentClass();
$hmm->getValues();
The output is
first value
second value
The intended output is
first value
blue value
third value
I feel like I'm overlooking something painfully simple. How can I achieve this? Or is my thought process completely left field?
You can't call a child's method from its parent, but you can call a parent method from a child.
Depending on what final outcome you are trying to achieve, you might try overriding one of the parent methods in the child class. For example:
class childClass extends parentClass
{
public function curValues()
{
$this->value1 = 'first value';
if (2 > 1) {
$this->value2 = 'blue value';
$this->value3 = 'third value';
}
}
}
And then create an instance of the child class instead of the parent class:
$hmm = new childClass();
$hmm->getValues();
Related
Say I have class child() and class parent(). The parent has a constructor and a few other public methods, and the child is empty apart from a constructor.
How do I go about calling a parent's methods inside of the child's constructor, as in:
Class Parent {
public function __construct() {
// Do stuff (set up a db connection, for example)
}
public function run($someArgument) {
// Manipulation
return $modifiedArgument;
}
}
Class Child extends Parent {
public function __construct() {
// Access parent methods here?
}
}
Say I want to call parents run() method, do I have to call a new instance of the parent inside the child constructor? Like so...
$var = new Parent();
$var->run($someArgument);
If so, what is the point of extends from a class definition POV? I can call a new instance of another class with the new keyword whether it extends the 'child' or not.
My (likely) wrong understanding was that by using extends you can link classes and methods from a parent can be inherited into the child. Is that only outside the class definition? Does using extend offer no efficiencies inside the class definition?
Because referring to the parent's run() method with the this keyword certainly doesn't work...
Use parent as predefined reference: parent::run(). This will ensure you call parent method. The same way you could call first parent constructor first or after child one - parent::__construct().
Class Child extends Parent {
public function __construct() {
parent::__construct();
// Access parent methods here?
$some_arg = NULL; // init from constructor argument or somewhere else
parent::run($some_arg); // explicitly call parent method
// $this->run($some_arg); // implicitly will call parent if no child override
}
}
If you dont have an implementation in child you could call $this->run($args), where it will again call parent run method.
To extend Rolice's answer
function a() {
echo 'I exist everywhere';
}
class A {
protected $a
function a() {
$this->a = 'I have been called';
}
function out() {
echo $this->a;
a();
}
}
class B extends A {
function __construct() {
parent::a();// original method
$this->a(); // overridden method
a();
}
function a() {
$this->a = $this->a ? 'I have been overwritten' : 'first call';
}
}
Study these to understand the difference
<?php
class HTML
{
protected $name;
public $id;
private $with;
protected function basicAttribute()
{
return "name='$this->name' id='$this->id'";
}
}
Class HTML_div extends HTML
{
public function __construct($id , $name)
{
$this->id = $id;
$this->name = $name;
}
public function getDiv($content)
{
$basicAttribute = $this->basicAttribute();
echo "<div $basicAttribute >$content</div>";
}
}
$objDiv = new HTML_div("bloc_main" , 'avc');
$objDiv->getDiv('this is and example of inheritance in php');
Question:
If I change $basicAttribute = $this->basicAttribute(); to $basicAttribute = parent::basicAttribute();, It also works. So I wonder what is the difference between them? and which is the better way to call parent method?
In this exact circumstance, they do the same thing. However, it's generally better to use $this->basicAttribute().
What each of those calls does is this:
$this->basicAttribute() -- calls child's implementation of basicAttribute() if one exists, otherwise looks to the closest ancestor for an implementation (in this case there is only a parent and child, so it calls the parent)
parent::basicAttribute() -- calls closest ancestor's implementation (in this case again, the parent). This will ignore an implementation of basicAttribute() in the child class, so it is advisable to only use it if you override a parent function and want to explicitly call the parent.
It is quite simple, really. When you extend a class, the new class inherits all the attributes and methods from that class (with the exception of properties and methods that are private). The class that is extended is called the parent class, and the class that is extending is called the child class.
So, if we have a class that looks something like this:
HTML
basicAttribute()
and we extend it:
HTML_div extends HTML
basicAttribute() // This method is automatically inherited from HTML
// which means that you do not have to create it yourself
So, when you call parent::basicAttribute() from HTML_div you are really calling HTML's method.
I believe this example should explain it in a way that is easy to understand:
class A {
function test() {
echo 'A';
}
}
class B extends A {
function test() {
echo 'B';
}
function parentTest() {
parent::test();
}
}
$b = new B;
$b->test(); // 'B'
$b->parentTest(); // 'A'
I'm having trouble understanding why I can access a property from my parent class, but it's NULL, even though it has already been set by the parent (and has not been knowingly reset). I thought it might be because that property was set by a private method, but no difference when I changed to public. Here's a radically simplified example:
class TheParent
{
protected $_parent_property;
function __construct()
{}
private function parent_method($property);
{
$this->_parent_property = $property;
$call = new TheChild;
$call->child_method();
}
}
class TheChild extends TheParent
{
function __construct()
{
parent::construct();
}
public function child_method();
{
echo $this->_parent_property;
exit;
}
}
$test = new TheParent;
$test->parent_method('test');
I worked around this by passing the parent property to the child when the child is constructed by the parent ie new TheChild($this->_parent_property), but I still don't understand why $this->_parent_property is set to NULL when accessed from the child in my original example.
I do know that if I set this property from the parent constructor, I'd be able to access it just fine. I'm trying to understand why a property set by a parent method, and accessible by other parent methods, is not accessible from the child class which extends the parent.
Can anyone explain? Thanks!
The problem is that you're creating a new instance where the variable isn't set. The property is bound to a particular instance, so you're creating one instance of the parent and then from the parent another instance of the child,i which includes all the stuff creating a new parent would contain, including $_parent_property. When you read the value in the child, you're reading the value of a newly created parent, not the one you previously created.
In effect, you do this:
A = new TheParent()
A->_parent_property = 'test'
Calls:
B = new TheChild() underneath the covers, this does new TheParent()
Print B->_parent_property (which was uninitialized)
Consider this similar example that will produce your expected result:
class TheParent
{
protected $_parent_property;
function __construct()
{
parent_method();
}
private function parent_method();
{
$this->_parent_property = 'test';
}
}
class TheChild extends TheParent
{
function __construct()
{
parent::construct();
}
public function child_method();
{
echo $this->_parent_property;
exit;
}
}
$child = new TheChild();
$child->child_method();
In this example, the private method in TheParent is invoked on the same instance created by TheChild, setting the underlying instance variable.
You have a slightly wrong idea of how inheritance works.
TheParent is a class, and TheChild is a class based on the TheParent. $test now is an instance of TheParent. It has no idea that there is another class TheChild based on the class TheParent.
You create a new instance $call which is of type TheChild. This is, to use another word, a new object. It has nothing to do with $test, except that both are "compatible" to TheParent.
TheChild ($call) inherits the property _parent_property from its parent (class). However, that property is not initialised/set in that instance (object), so it is still NULL.
is there a way to traverse an object to get the parent object data?
With "parent object" I don't mean the parent class, but literally object.
Here an example, in a javascripty world :-) :
$parent->test = "hello world!";
$parent->child = new B();
It would be great If I could access all the data from parent in the child object:
class B{
//I know this doesn't exists, but it's what I wanted do do
function B(){
$this->parent = $this->parent();
echo $this->parent->test; //it would ouput "hello world"
}
}
For now my solution is to pass the parent object to the child (as a reference) or to make the parent global.
Do you have any better solution?
Thanks!
There is no way to invoke
$parent->test = "hello world!";
$parent->child = new B();
and automatically have a reference to $parent in B.
Generally, there is four ways to structure your classes:
1. Aggregate the parent object via Injection, e.g.
class B
{
private $parent;
public function __construct($parent)
{
$this->parent = $parent;
}
public function setParent($parent)
{
$this->parent = $parent;
}
public function accessParent()
{
$this->parent->someMethodInParent();
}
}
Use constructor injection when the object has to have a parent when it's created. This is a has-a relationship and it creates a very loose coupling. There is no hardcoded dependencies in B, so you can easily swap out the Parent instance, for instance with a Mock when UnitTesting. Using Dependency Injection will make your code more maintainable.
In your UseCase, you'd pass $parent to B when creating B:
$parent->child = new B($parent);
2. Use Composition
class B
{
private $parent;
public function __construct()
{
$this->parent = new Parent;
}
public function accessParent()
{
$this->parent->someMethodInParent();
}
}
This is also a has-a relationship, but couples the Parent class to B. It's also not an existing Parent instance, but a new instance. From the wording I find it somewhat odd to have a parent created by the child. Use this, when dependency is a class that is not considered to exist outside of the root class, but is part of the whole thing it represents.
For your UseCase, there is no way of doing $parent->child = new B(); and know what parent is when using this approach, unless $parent is a Singleton. If so, you could get the Singleton instance, e.g. Parent::getInstance() to achieve what you want, but note that Singletons are not everyone's favorite pattern, e.g. hard to test.
3. Use Inheritance
class B extends Parent
{
public function accessParent()
{
$this->someMethodInParent();
}
}
This way you create an is-a relationship. All public and protected methods and properties from the Parent class, (but not of a specific instance) will be available in B and you can access them via the $this keyword of the B instance.
For your UseCase, this approach is not working, as you don't have to have an instance of Parent at all, but B would encapsulate everything of Parent when it's created
$b = new B;
4. Use global keyword
class B extends Parent
{
private $parent;
public function __construct()
{
global $parent;
$this->parent = $parent;
}
public function accessParent()
{
$this->parent->someMethodInParent();
}
}
The global keyword imports global variables into the current scope. In general, you should avoid using the global keyword in an OO context, but use one of the other three methods above, preferably the first one. While it's a language feature, it's frowned upon - although it is the next closest thing to the first one, e.g.
$parent->child = new B();
Anyway, hope that helps.
Passing the parent to the child is the better solution. Though it's a somewhat undesirable symbiotic relationship.
Should B() have any knowledge of the object it's an attribute of? More than likely not. These are only loosely related via composition.
Why does B() need to be an attribute of it's parent? Do you need to have this implementation in B() or should it be part of the parent?
Maybe it can be useful in some case: it doesn't bring parent object to ChildClass very early in constructor, but a one step later. It plays with ability to intercept non-existing method:
class ParentClass
{
const CHILD_PROPERTY_NAME = 'child';
public $data = 'Some data';
public function
__set($property_name, $property_value)
{
if ($property_name == self::CHILD_PROPERTY_NAME)
{
$property_value->set_parent_object($this);
}
}
}
class ChildClass
{
private $parent_object = null;
public function
set_parent_object($object)
{
$this->parent_object = $object;
echo $this->parent_object->data;
}
}
$p = new ParentClass();
$p->child = new ChildClass();
This will output Some data
I'm pretty sure, that PHP does not have something like that.
Your solution of passing the parent-object to the child is the best solution, I think. You should consider to set your Parent-property only in the constructor of the child to prevent multiple parents from having the same child.
No.
You can access variables from the superclass using $this:
<?php
class A {
public function __construct()
{
$this->foo = 'hello';
}
}
class B extends A {
public function printFoo()
{
echo $this->foo;
}
}
$b = new B();
$b->printFoo();
?>
You can create collections of object children when you create the children. you create it trough the parent this way they cannot reference each other but you can access both parents and children trough the parent and trough the children...
class ChildObject
{
public $name;
}
class ParentObject
{
public $children = array();
public function new_child($text = 'my name is data')
{
$child = new ChildObject; // create a new child
$child->name = $text; // assign the name
$this->children[] = $child; // store it as part of this object
return $child; // return the new instance of Child
}
public function print_everything ()
{
foreach($this->children as $child) {
echo $child->name;
}
}
}
$parent = new ParentObject;
$child1 = $parent->new_child(); // this is a ChildObject not a ParentObject
$child2 = $parent->new_child('i am not data');
echo $child1->name; // 'my name is data'
echo $child2->name; // 'i am not data'
$child1->name = 'something else';
echo $child1->name; // 'something else'
$parent->print_everything(); // 'something else' and 'i am not data'
Therefore if you want to access a parent method or property, you should put that in the parent and not in the child. Remember that the parent is also an "instance" of its own class.
I'm trying to get the following to work, but I'm at a loss...
class Foo {
public $somethingelse;
function __construct() {
echo 'I am Foo';
}
function composition() {
$this->somethingelse =& new SomethingElse();
}
}
class Bar extends Foo {
function __construct() {
echo 'I am Bar, my parent is Foo';
}
}
class SomethingElse {
function __construct() {
echo 'I am some other class';
}
function test() {
echo 'I am a method in the SomethingElse class';
}
}
What I'd like to do is create an instance of the SomethingElse class within the class Foo. This works using =&. But when I extend class Foo with class Bar, I thought that the child inherits all the data attributes and methods from the parent class. However, it seems that $this->somethingelse doesn't work in child class Bar:
$foo = new Foo(); // I am Foo
$foo->composition(); // I am some other class
$foo->somethingelse->test(); // I am a method in the SomethingElse class
$bar = new Bar(); // I am Bar, my parent is Foo
$bar->somethingelse->test(); // Fatal error: Call to a member function test() on a non-object
So, is it not possible to inherit in such a way? And should I create a new instance of class SomethingElse from within class Bar if I want to use it there? Or am I missing something?
Thanks in advance for your help.
I thought that the child inherits all the data attributes and methods from the parent class.
This is true - the child class inherits the static variables and static methods from the parent class. Additionally, any child objects will inherit the static and instance variables and methods.
One possibility to get what you want with your existing class structure is this:
$bar = new Bar();
$bar->composition();// here you are calling the parent method, sets instance var $somethineelse
$bar->somethingelse->test();// now you can call methods
Another way to accomplish inheriting an variable (in this case an object) in child instances would be like so:
class Foo {
protected $somethingelse;
public function __construct() {
$this->somethingelse = new SomethingElse();
}
}
class Bar extends Foo {
public function __construct() {
parent::__construct();
// now i've got $somethingelse
}
}
For a very good overview of classes and objects in PHP 5, take a look here:
http://php.net/manual/en/language.oop5.php
Make sure to read it all, maybe a couple times if OO is new for you.
bar has a member variable named somethingelse, which is inherited from foo.
you are mixing object and class scope.
if you really want to achieve the effect described, you have to make your variable static, so its context is class based
First, you have to distinguish between static and instance variables. Static variables are shared among all instances of a class, instance variables are not.
If you want every instance of Foo and Bar to have the exact same SomethingElse-Instance you have to make $somethingelse static:
public static $somethingelse
and you should change the composition-function of Foo:
function composition() {
self::$somethingelse = new SomethingElse();
}
To access this static field you can do the following:
$foo = new Foo(); // I am Foo
$foo->composition(); // I am some other class
Foo:$somethingelse->test(); // I am a method in the SomethingElse class
$bar = new Bar(); // I am Bar, my parent is Foo
Bar::$somethingelse->test(); // I am a method in the SomethingElse class
If you want every instance of Foo and Bar have their own SomethingElse instance you can use your code, but you need to add
$bar->composition()
before $bar->somethingelse->test();
That's because with
$bar = new Bar();
you created a completely new instance of Bar and that instance has a $somethingelse property, but it has not been set yet. So you need to call composition() to set it.
If every Foo and Bar should have the exact same SomethingElse-instance, you should use the static version instead, because it reduces the memory needed.
I hope this can help you. Otherwise I am very happy to explain it further.
Saying that classes share attributes doesn't mean that the objects share attribute values.
As others have noted, you are confusing classes with instances.
Note, you'd get the same error if you did:
$foo = new Foo(); // I am Foo
$foo->composition(); // I am some other class
$foo->somethingelse->test(); // I am a method in the SomethingElse class
$foo2 = new Foo(); // I another Foo
$foo2->somethingelse->test(); // Fatal error: Call to a member function test() on a non-object
Think of the classes less abstractly. For example, you might have a class, "Person," which is a parent class of "Royalty."
Then if you did:
$me = new Person();
$me->firstName = "Thomas"
$princeCharles = new Royalty();
You wouldn't want $princeCharles to have the a firstName attribute equal to "Thomas," and if you want to set $princeCharles->firstName, you don't that to change the value of the firstName attribute of $me.
Both $me and $princeCharles have an attribute 'firstName', but we don't share the value of that attribute.
I think your problem will be solved if in the derived class constructor will call the parent class constructor. This does not occur by default in PHP so keep it in mind when you have issues with inheriting data members.
class Bar extends Foo {
public function __construct() {
parent::__construct();
}
}