Does this smell if I cant decide which descendant should I use? - php

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

Related

PHP Use child variable to create a class in parent class

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.

Cannot create object in class PHP

I try to create object in PHP class, but i get some interesting errors in IDE, like unexpected ( token etc. Here is my code:
class A {
public $a = 1;
}
class B {
$aa = new A();
}
Where is the problem?
In PHP, you can only assign "fixed" values to properties in the class definition.
class A {
public $a = 3; // will work
public $b = "hello"; // will work
public $c = foo(); // won't work
public $d = new Foo(); // won't work
}
If you want to do so, you can use the __construct() method which will be called every time a new instance is created or any other method that you call.
class B {
public $aa; // define visibility of $aa
function __construct() {
$this->aa = new A();
}
}
You need to make a constructor on class A
class A {
function __construct() {
$this->a = 1;
}
public function returnA() {
return $this->a;
}
}
$aa = new A();
echo $aa->returnA();
Try to create a constructor in class A and see if it works:
class A {
public $a;
function __construct()
{
$this->$a = 1;
}
}
class B {
$aa = new A();
}

Simulate multiple inheritance in PHP

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

Copying an instance of a PHP class while preserving the data in a base class?

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

transfer variables between class A and B

How i can run method $this->ob->getVar() inside class B function C here ? I get no. Did i must transfer string to constructor ?
<?php
class A{
public $tabb = array('1'=>'one', '2'=>'two');
public $index;
public function setVar($v){
$this->index = $v;
}
public function getVar(){
return $this->index;
}
public function arr(){
return $this->tabb;
}
}
class B{
public $tab;
public function __construct($var){
$this->ob=new A;
$this->tab = $var;
}
public function C(){
return $this->D($this->tab, $this->ob->getVar());
}
public function D($l, $j){
if(is_array($l) && isset($j)){
print 'yes';
} else {
print 'no';
}
}
}
$obb = new A;
$obb->setVar('onetwo');
$k = $obb->arr();
$obbb = new B($k);
$obbb->C();
?>
First, for the sake of convention your B class should declare a private variable of $obj, but that is not necessary in PHP.
Second, your B class is just creating a new instance of A in its constructor. So you have two different A classes. The once inside B never has its index property populated.
If you wanted to have the A object created outside the B object you'll have to pass it in like this:
$obbb = new B($k, $obb);
So now your new B constructor is something like this:
public function __construct($var, $someObject){
if (!empty($someObject)) {
$this->ob = $someObject;
}
else {
$this->ob=new A;
}
$this->tab = $var;
}

Categories