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.
Related
I've got a class
class foo {
function do_something() {
load();
}
function load() {
//things
echo 'load from foo';
}
}
And another class that extends foo (a child class):
class bar extends foo {
function load() {
//things
echo 'load from bar (child)';
}
}
And then:
$obj = new bar();
What I want to know is how can I call $obj->do_something() such that the method uses the child 'load' method instead of the method declared in the foo class.
So, I want the output to be:
$obj->do_something();
Output: load from bar (child)
Is this possible with PHP?
Thanks!
You need to qualify the object context with $this. Unlike some other languages, PHP requires that you qualify the instance explicitly with $this for all method calls from within an object.
class foo {
function do_something() {
// load();
$this->load();
}
function load() {
echo 'load from foo';
}
}
class bar extends foo {
function load() {
echo 'load from bar (child)';
}
}
$obj = new bar();
$obj->do_something();
In your code (merely calling load()) the language was looking for a globally defined function named load, which of course wouldn't work (or in worse cases, would but incorrectly)
As another answer points out, you must similarly qualify static methods though the use of self or static (which I would suggest you read up on to understand the binding differences)
From an inheriting class, in an overriding method, you can also use parent to invoke the parent classes' definition of the method:
class bar extends foo {
function load() {
parent::load(); // right here
echo 'load from bar (child)';
}
}
This will invoke the parent's version of the load method, and continue execution with the child classes' definition.
I would recommend use abstract function if you want to have such a tight coupling of methods. it's going to require high maintenance and you are creating some tight couplings between classes.
i would recommend creating an abstract function in the parent that each of the children will implement with it's own logic.
Even then if you want change your parent class function to this
function do_something(){
if(method_exists($this, 'test')){
$this->test();
}
}
you can use abstract class and abstract method:
abstract class Foo{
function test() {
$this->method();
}
abstract function method();
}
class Test extends Foo {
function method() {
echo 'class Test';
}
}
$test = new Test();
$test->test();
Try this
class foo {
function do_something() {
static::load();
}
function load() {
//things
echo 'load from foo';
}
}
class bar extends foo {
function load() {
//things
echo 'load from bar (child)';
}
}
$obj = new bar;
$obj->do_something();
Consider the following snippet:
class A {
private function foo() {}
protected function bar() {}
}
class B extends A {
private function baz() {}
}
$r = new ReflectionClass('B');
foreach ($r->getMethods() as $method) {
echo $method->getName() . PHP_EOL;
}
I would expect the following output:
baz
bar
But the actual output is:
baz
foo
bar
Why does getMethods() return private methods from parent classes, and therefore out of the scope of the class being reflected, B?
I'm wondering if there is any rationale behind this, or if this is a bug that should be filed?
No, it's not a bug. This function does exactly what it designed for. Also, check out the link you gave in your question, there is a filter parameter, which can be used to set attributes of methods to return.
While trying to get a legacy codebase under test, I've come across an object that does the following:
class Foo
{
public function __construct($someargs)
{
$this->bar = new Bar();
// [lots more code]
}
}
Bar in this instance has a constructor that does some Bad Things e.g. connecting to a database. I'm trying to concentrate on getting this Foo class under test so changed it to something like this:
class Foo
{
public function __construct($someargs)
{
$this->bar = $this->getBarInstance();
// [lots more code]
}
protected function getBarInstance()
{
return new Bar();
}
}
And have attempted to test it via the following PHPUnit test:
class FooTest extends PHPUnit_Framework_TestCase
{
public function testInstance()
{
$bar = $this->getMock('Bar');
$foo = $this->getMock('Foo', array('getBarInstance'));
$foo->expects($this->any())
->method('getBarInstance')
->will($this->returnValue($bar));
}
}
However this doesn't work - the constructor of Foo() is called before my ->expects() is added, so the mocked getBarInstance() method returns a null.
Is there any way of unlinking this dependency without having to refactor the way the class uses constructors?
Use the $callOriginalConstructor argument of getMock(). Set it to false. It's the fifth argument of the method. Look it up here: http://www.phpunit.de/manual/current/en/api.html#api.testcase.tables.api
Actually, hold on. You want to pass a mock to a mock? If you really want this, then use the third argument of getMock which represents the arguments to the constructor. There you can pass the mock of Bar to the mock of Foo.
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();
}
}
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!');