PHP5 Classes: inheriting a composed class? - php

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();
}
}

Related

OOP PHP: Using parent's static element in declaration of child static element?

I'm trying to write a class that uses its parent's static declared array to add a new value to. Below is kind of a feel of how I'm trying to run it...
class SuperClass
{
protected static $array_name = array('value1');
}
class SubClass extends SuperClass
{
protected static $array_name = array_push(parent::$array_name, 'value2');
}
Is there any way to properly implement this without a __construct() function?
I'm trying to implement a static working model for the SuperClass and its parents...
I'm not entirely sure if you want static classes completely, but this does what you want give or take :
<?php
class SuperClass
{
static $array_name = array('value1');
}
class SubClass extends SuperClass
{
static $array_name = 'foo';
function __construct(){
self::$array_name = array_push(parent::$array_name, 'value2');
}
}
$foo = new SubClass();
var_dump($foo::$array_name); // prints INT 2 - as push returns number of elements in array.
?>

PHP - How to call function from an upstream object

I have a DB interface object, DBI, that requires authentication. I have an object, foo, that doesn't extend anything. I also have a class bar that extends the DBobject If I have an instance of foo that is a member of bar thus:
$b->$f=new foo;
How can I call somefunction() in $b from a function inside the foo class? I've tried making the somefunction() static, but I don't want the authentication info sprinkled throughout my code. And if I try having foo extend the DBI or bar classes, I wind up with an issue including the files and my foo __construct function fails because the bar class is not found. Is there another construct similar to extends/parent:: that I can use with objects that are just instances amongst each other?
The way that I've done this in the past, is create the Foo object within the Bar object within the __construct(). Then utilize the __call magic method to intercept the methods and see where it is. So the code could look something like this:
public function __call($sMethod, $aArgs) {
if(method_exists($this, $sMethod){
return call_user_func_array(array($this, $sMethod), $aArgs);
}
} elseif(method_exists($this->foo, $sMethod)) {
return call_user_func_array(array($this->foo, $sMethod), $aArgs);
}
}
public function __construct() {
$this->foo = new foo();
}
Then you can call the functions from either foo or bar, even though they are not extended. Just a though, maybe there is an easier way to do this.
** EDIT **
The benefit to this is you don't need to specify whether or not you are calling a method from foo or from bar, they will just "work".
** EDIT **
Based on the comments, you want to do this, correct? Because based on the code below, if you run it it works correctly.
class foobar {
public function test() {
echo 'This is a test';
}
}
class foo extends foobar {
}
class bar {
}
$bar = new bar();
$bar->foo = new foo();
$bar->foo->test();
or the alternative:
class foobar {
public function test() {
echo 'This is a test';
}
}
class foo extends foobar {
}
class bar {
public function testFooBar() {
$this->foo->test();
}
}
$bar = new bar();
$bar->foo = new foo();
$bar->testFooBar();
Both work at long as you know the property name you are setting for the object.
In addition to call_user_func and call_user_func_array, if you want to access methods and properties of the container object (not parent class), you need a reference to it. Here is a similar post.

PHP overloaded static property and static method

Situation: I have a class that has a static property, a static method and a few abstract elements that aren't too interesting right now. Here's my first class:
abstract class Parent
{
public static $property = 'Foo';
public static function func()
{
echo self::$property
...
}
}
Now the fun begins. I want to extend this class, overload the static property, use the same not overloaded method.
class Child extends Parent
{
public static $property = 'Bar';
}
Child::func(); //Output: 'Foo'
Thw problem is, I always get 'foo' (eg. the parent's default property value). What do I do wrong?
In ParentClass (since the word Parent is a reserved keyword) change...
echo self::$property;
...to this...
echo static::$property;

Parent class property set by parent method blank when accessing from child method

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.

Accessing a class that has been instantiated by a method within a separate class

In a nutshell: how do I access the methods of a class that is instantiated by a method of a different class?
There is a bit of code I am looking at right now that does the following (altering the code is not an option, btw. It isn't mine... I'm just decipher it):
A class has a method that instantiates a different class. It looks something like this:
// this file is named fooClassHere.php
class Foo{
public $meh;
function bar(){
$something = new Baz;
$this->meh = $something->getStuff();
}
}
What I am trying to figure out is how to access the methods of this instantiated class Baz. Another page contains something like the following:
include 'bazClassHere.php';
include 'fooClassHere.php';
$a = new Foo;
$a->bar();
So shouldn't all of Baz be available now in some manner (and not just getStuff() which I assigned to $this->meh)? The Foo and Baz classes are included, the code instantiates Foo and then calls Foo's method bar() which in turn instantiates the Baz class. Obviously the following will display data returned by Baz's getStuff() method:
var_dump($a->meh);
But I'd like to access all of Baz's available methods without going through the intermediate step of manually assigning them like I did inside Foo's bar method: $this->meh = $something->getStuff()
Maybe something like (but of course this doesn't work):
$a = new Foo;
$a->bar(); //instantiates Baz as $something
$a->something->fromBaz(); //$something is an instance of Baz, yes? No?
I hope this makes sense and I didn't confuse the issue with my notes. Ack! >_<
If altering the code is not an option, you're out of luck. To achieve what you want you do this:
class Foo {
public $meh;
public $something;
function bar(){
$this->something = new Baz;
$this->meh = $this->something->getStuff();
}
}
And then later on you can do:
$foo = new Foo;
$foo->something->myBazMethod();
You could use __call on your Foo class, look it up on php.net
Basically, __call gets called when you try to call a function that the class doesn't have. In there, you could pass the request to your inner object instead.
class a
{
protected $b;
public function __construct()
{
$this->b = new b();
}
public function meh()
{
return 'meh';
}
public function __call($func, $param)
{
return call_user_func_array(array($this->b, $func), $param);
}
}
class b
{
public function yo($something)
{
return $something;
}
}
$a = new a();
echo $a->meh();
echo $a->yo('dude!');

Categories