Assuming I have 2 classes
Class A {
public function doA(){
echo "Im A";
}
}
Class B {
public function doB(){
echo "Im B";
}
}
write Class C, in order that the following code runs:
$c = new C();
$c->doA();
$c->doB();
and outputs:
>> Im A
>> Im B
This was in a test, and the conditions where:
use no static calls
you can't modify class A or class B
so I wrote:
Class C {
public function doA() {
$a = new A();
$a->doA();
}
public function doB() {
$b = new B();
$b->doB();
}
}
So apparently I was wrong as it can be "more optimized"
can someone tell me how to do it?
You could keep instances of A and B instead of instantiating them each time.
class C {
private $a, $b;
public __construct() {
$this->a = new A();
$this->b = new B();
}
public function doA() {
$this->a->doA();
}
public function doB() {
$this->b->doB();
}
}
PHP has no "native" multiple inheritance, but you can achieve something similar to it by using traits.
Trait A {
public function doA(){
echo "Im A";
}
}
Trait B {
public function doB(){
echo "Im B";
}
}
Class C {
use A, B;
}
$c = new C;
$c->doA();
$c->doB();
Note that this would require at least PHP 5.4.
To do it without modifying classes, the best and optimised option would be as follows.
class C {
private $a;
private $b;
public __construct() {
$this->a = new A();
$this->b = new B();
}
public function __call($method, $arguments = array()) {
if(method_exists($this->as, $method)) {
return call_user_func(array($this->a, $method));
}
}
}
The above is also future proof, so adding new methods would also follow.
While you were told not to modify classes A and B, the correct way to do this would be by having B extend A, then having C extend B, like below.
class A {
public function doA(){
echo "Im A";
}
}
class B extends A {
public function doB(){
echo "Im B";
}
}
class C extends B {
}
$c = new C();
$c->doA();
$c->doB();
Related
I would like to bind a function (a method of a class) to another class. Any idea of how i could achieve this?
Here is an example of what i want:
class A {
protected $prop = "prop A";
function method($arg1, ...) {
return $this->prop;
}
}
class B {
protected $prop = "prop B";
// need help here
}
So i want to "bind" the method "method" of class "A" to class "B" so it'll be possible to do $b = new B(); $b->method($arg1, ...); and obtain "prop B";
Thanks in advance!!
I tried:
class B {
protected $instance;
protected $prop = "prop B";
public function __construct($instance) {
$this->instance = $instance;
}
public function __call($method, $args) {
return call_user_func_array([$this->instance, $method], $args);
}
}
$b = new B(new A());
$b->method();
But still outputing "prop A";
I tried this too:
class B {
protected $prop = "prop B";
public function __call($method, $args) {
return call_user_func_array(Closure::bind($this->$method, $this, get_called_class()), $arguments);
}
}
$a = new A();
$b = new B();
$b->method = $a->method;
$b->method();
But i'm getting this error: Closure::bind() expects parameter 1 to be Closure, null given....
At last i tried this too:
class B {
protected $instance;
protected $prop = "prop B";
public function __construct($instance) {
$this->instance = $instance;
}
public function __call($method, $args) {
$new_method = $this->instance->$method->bindTo($this);
return call_user_func_array($new_method, $args);
}
}
$b = new B(new A());
$b->method();
Here, an error says $this->instance->$method is null
Using dependency injection, you can access the passed object:
class A {
public function speak() { return ‘meow’; }
}
class B {
public function __construct($obj) {
$this->a = $obj;
}
}
$demo = new B( new A));
print $demo->a->speak();
// => meow
From here, if you want B->speak to refer to A->speak:
class A {
public function speak() { return ‘meow’; }
}
class B {
public function __construct($obj) {
$this->a = $obj;
}
public function speak() {
return $this->a->speak();
}
}
$demo = new B( new A));
print $demo->a->speak(); // meow
print $demo->speak(); // meow
Or, if B is a special kind of A:
// use obj A above
class B extends A {
// do stuff B knows
}
$demo = new B;
print $demo->speak();
// => meow
If you’re wanting the exact same method in both classes, perhaps what you’re looking for is traits. Traits are more or less an include for objects which lets objects “share” code. (Personally I think it’s a fancy way of violating DRY and is better handled with DI... but smarter people than I have included it in the language)
Using traits would be something like this (double check docs, I’ve never used this)
trait sharedMethod {
public function speak() {
return $this->prop;
}
}
class A {
use sharedMethod;
public $prop = “I’m from A”;
}
class B {
use sharedMethod;
public $prop = “I’m from B”;
public function __construct(object $a) {
$this->a = $a;
}
/**
* use this to get A’s method, or omit to keep B’s method
*/
public function speak() {
return $this->a->speak();
}
}
$demo = new B( new A));
print $demo->speak(); // I’m from A
// if you don’t override the method
$demo = new B( new A));
print $demo->speak(); // I’m from B
abstract class X
{
private $v;
protected function setV($v)
{
$this->v = $v;
}
public function getV()
{
return $v;
}
}
class A extends X
{
public function doIt()
{
parent::setV(1);
}
}
class B extends X
{
public function doIt()
{
parent::setV(2);
}
}
$a = new A();
$a->doIt();
$b = new A();
$b->doIt();
but if I want to use getV(), I can both call
$a->getV() and $b->getV()
which sounds silly. Which one to use? To be honest, I would like to see something like that:
X::getV();
which is not possible, an instance must be exists/
It depends on "what do you want". Firstable, it's possible to use X::getV() method, but you need to make v member and getV method static, as shown below.
<?php
abstract class X
{
private static $v;
protected static function setV($v)
{
self::$v = $v;
}
public static function getV()
{
return self::$v;
}
}
class A extends X
{
public function doIt()
{
self::setV(2);
}
}
class B extends X
{
public function doIt()
{
self::setV(1);
}
}
$a = new A();
$a->doIt();
echo X::getV();
// prints 2
// but be aware, that ANY instance of X children class will change the same X::$v value
$b = new B();
$b->doIt();
echo X::getV();
// prints 1
Static members (like X::$v) are stored only once, they are "binded" to the class, not to the instance of this class.
<?php
class Foo
{
public static $v = 5;
}
$instance1 = new Foo();
$instance2 = new Foo();
echo Foo::$v;
echo $instance1::$v;
echo $instance2::$v;
// prints 5, 5, 5
$instance1::$v = 10;
echo Foo::$v;
echo $instance1::$v;
echo $instance2::$v;
// prints 10, 10, 10
I have 3 classes:
Class A - Parent Class
Class B - Child Class
Class C - Class to be used in Class A
I want to use functions from class C using variables from my Child class.
<?php
class A
{
public function __construct()
{
$this->load();
}
public function load()
{
$class = new C();
$class->test = $this->test;
$this->c = $class;
}
}
class B extends A
{
public function __construct()
{
parent::__construct();
}
}
class C
{
public function display()
{
echo $this->test;
}
}
$b = new B();
$b->test = 1;
$b->c->display();
Your problem is here:
$class->test = $this->test;
You are attempting to use a property that is not yet defined, because when you do this:
$b->test = 1;
the constructor has already been called, and there's nothing in your classes to update C with the value of B's test property.
You can solve this in a couple of different ways.
1) Send the value in B's constructor, and pass it down the entire chain:
class A
{
public function __construct($test)
{
$this->load($test);
}
public function load($test)
{
$class = new C();
$class->test = $test;
$this->c = $class;
}
}
class B extends A
{
public function __construct($test)
{
parent::__construct($test);
}
}
class C
{
public function display()
{
echo $this->test;
}
}
$b = new B(123);
$b->c->display();
2) Add a method to B that will update C's property:
<?php
class A
{
public function __construct()
{
$this->load();
}
public function load()
{
$class = new C();
$this->c = $class;
}
}
class B extends A
{
public function __construct()
{
parent::__construct();
}
public function setTest($test)
{
$this->c->test = $test;
}
}
class C
{
public function display()
{
echo $this->test;
}
}
$b = new B();
$b->setTest(123);
$b->c->display();
Or perhaps a combination of both.
I have a base class and multiple classes that extends from the base class.
class B {}
class C extends B {}
class D extends B {}
How can I create a C or D inside the method dynamically from B? what's the best way?
For example I tried:
class B {
function hello() { echo "hello"; }
function createObject()
{
$temp = new self();
$temp->hello();
}
}
$t = new C();
$t->createObject();
You're right! But you must return your new object like:
class B {
function hello() { echo "hello"; }
function createObject()
{
$temp = new self();
$temp->hello();
return $temp; // <--- here
}
}
$t = new C();
$tNew = $t->createObject();
I have the following three classes:
class a
{ public $test; }
class b extends a { }
class c extends a
{
function return_instance_of_b() { }
}
As you can see, both classes b and c derive from a. In the return_instance_of_b() function in c, I want to return an instance of the class b. Basically return new b(); with one additional restriction:
I need the data from the base class (a) to be copied into the instance of b that is returned. How would I go about doing that? Perhaps some variant of the clone keyword?
You can use the get_class_vars function to retrieve the names of the variables you want to copy, and just loop to copy them.
The variables that are defined are protected so they are visible to get_class_vars in its scope (since c extends a), but not directly accessible outside the class. You can change them to public, but private will hide those variables from get_class_vars.
<?php
class a
{
protected $var1;
protected $var2;
}
class b extends a
{
}
class c extends a
{
function __construct()
{
$this->var1 = "Test";
$this->var2 = "Data";
}
function return_instance_of_b()
{
$b = new b();
// Note: get_class_vars is scope-dependant - It will not return variables not visible in the current scope
foreach( get_class_vars( 'a') as $name => $value) {
$b->$name = $this->$name;
}
return $b;
}
}
$c = new c();
$b = $c->return_instance_of_b();
var_dump( $b); // $b->var1 = "Test", $b->var2 = "Data
I believe you can achieve this with some reflection. Not very pretty code, I'm sure there is a much more succinct method to achieve this but here you go.
class a
{
public $foo;
public $bar;
function set($key, $value) {
$this->$key = $value;
}
function get($key) {
return $this->$key;
}
}
class b extends a
{
function hello() {
printf('%s | %s', $this->foo, $this->bar);
}
}
class c extends a
{
public $ignored;
function return_instance_of_b() {
$b = new b();
$reflection = new ReflectionClass($this);
$parent = $reflection->getParentClass();
foreach($parent->getProperties() as $property) {
$key = $property->getName();
$value = $property->getValue($this);
$b->$key = $value;
}
return $b;
}
}
$c = new c();
$c->set('foo', 'bar');
$c->set('bar', 'bar2');
$c->set('ignored', 'should be!');
$b = $c->return_instance_of_b();
$b->hello();
// outputs bar | bar2
Additionally you could use nickb's answer but instead of hard coding the class you could use get_parent_class
function return_instance_of_b()
{
$b = new b();
foreach(get_class_vars(get_parent_class(__CLASS__)) as $name => $value) {
$b->$name = $this->$name;
}
return $b;
}