I have
class A
{
$a;
$b;
$c
}
And
class B
{
$a;
$b;
$e;
$f
}
How can i copy all common property from A to B? I already try the clone method but it only give me 2 objects A.
Is there any way to do it generically?
If you're looking for class "copying", then do it via overriding via extends keyword:
class A
{
public $a, $b, $c;
}
class B extends A
{
public $d, $e, $f;
}
-now your B will inherit all properties from A which are not private (so $a, $b and $c as well)
But if it's about objects (for example, your classes are not related anyhow) - then use get_object_vars() to iterate:
class A
{
public $a=1;
public $b=2;
public $c=3;
}
class B
{
public $a=5;
public $b=6;
public $e=7;
public $f=8;
}
$foo = new A;
$bar = new B;
foreach(get_object_vars($foo) as $name=>$value)
{
if(property_exists($bar, $name))
{
$bar->$name = $value;
}
}
-check the fiddle. Note, that properties must be visible (public) to do this.
First way (inheritance) http://www.php.net/manual/en/language.oop5.inheritance.php
<?php
class A {
public $_x = 'x';
public $_y = 'y';
public $_z = 'zz';
}
class B extends A {
public function __construct() {
echo $this->_x . "__" . $this->_y . "__" . $this->_z;
}
}
$b = new B; // x__y__zz
?>
Second way - class instantiation - properties are public, so you can access their values from the object instance, and assign it to you inner properties
<?php
class AA {
public $_x = 'x';
public $_y = 'y';
public $_z = 'zz';
}
class BB {
public $_x, $_y, $_z;
private $_AA;
public function __construct() {
$this->_AA = new AA();
$this->_x = $this->_AA->_x;
$this->_y = $this->_AA->_y;
$this->_z = $this->_AA->_z;
echo $this->_x . "__" . $this->_y . "__" . $this->_z;
}
}
$bb = new BB; // x__y__zz
?>
Third way, if properties are private, and if you have direct access to the base class, you can make accessors to then, so even they cannot be overwritten from outside, their value can be accessed
<?php
class AAA {
private $_x = 'x';
private $_y = 'y';
private $_z = 'zz';
public function getX() {
return $this->_x;
}
public function getY() {
return $this->_y;
}
public function getZ() {
return $this->_z;
}
}
class BBB {
public $_x, $_y, $_z;
private $_AAA;
public function __construct() {
$this->_AAA = new AAA();
$this->_x = $this->_AAA->getX();
$this->_y = $this->_AAA->getY();
$this->_z = $this->_AAA->getZ();
echo $this->_x . "__" . $this->_y . "__" . $this->_z;
}
}
$bbb = new BBB; // x__y__zz
Generic :)
<?php
class AAA {
private $_x = 'x';
private $_y = 'y';
private $_z = 'zz';
public function getX() {
return $this->_x;
}
public function getY() {
return $this->_y;
}
public function getZ() {
return $this->_z;
}
}
class BBB {
public $_x, $_y, $_z;
}
$AAA = new AAA();
$BBB = new BBB();
$get = 'get';
$arr_AAA = (array)$AAA;
foreach($arr_AAA as $key => $value) {
$property = explode('_', $key);
$property = ucfirst($property[1]);
$getter[] = $get.$property;
}
$i = 0;
foreach (get_object_vars($BBB) as $k=>$v) {
$get = $getter[$i];
$BBB->$k = $AAA->$get();
$i++;
}
var_dump($BBB);
/**
object(BBB)[2]
public '_x' => string 'x' (length=1)
public '_y' => string 'y' (length=1)
public '_z' => string 'zz' (length=2)
*
*/
This should work for i.e.
private $_qwe = 'qwe';
public getQwe() {
return $this->_qwe;
}
It will uppercase the first letter as it should be the convention of the getters. Ofcourse you can build your own convention.
Related
What do this reference symbol (&) do in &methodName() method?
Is it necessary?
Is this called a reference by method?
class TestClass
{
private $value;
public function __construct()
{
$this->value = 5;
}
public function &methodName(){
return $this->value;
}
}
echo (new TestClass())->methodName(); //Outputs 5;
It means that the method returns a reference. If you then assign that to a reference variable outside the method, updating the variable will update the property.
class TestClass
{
private $value;
public function __construct()
{
$this->value = 5;
}
public function &refMethod(){
return $this->value;
}
public function valueMethod() {
return $this->value;
}
public function printValue() {
echo $this->value . "<br>";
}
}
$c = new TestClass();
$var1 = &$c->valueMethod();
$var1 = 10;
$c->printValue(); // prints 5
$var = &$c->refMethod();
$var = 20;
$c->printValue(); // prints 20
<?php
class S {
public $a = 'a';
protected $b = 'b';
private $c = 'c';
function get_last_child_public_properties () {
/* HOW TO */
}
}
class A extends S
{
public $d = 'd';
protected $e = 'e';
private $f = 'f';
}
class B extends A
{
public $g = 'public_g';
protected $h = 'h';
private $i = 'i';
public $j = 'public_j';
}
$b = new B();
$props = $b->get_last_child_public_properties();
/**
* I expect $props to be equals to :
* Array : ['g' => 'public_g', 'j' => 'public_j']
*/
You should have a look at the Relection-classes in PHP.
Specifically the getProperties()-method wich returns an array of all the properties in the object as instances of ReflectionProperty.
$classInfo= new ReflectionClass($b);
foreach($classInfo->getProperties() as $prop) {
if ($prop->isPublic() && $prop->getDeclaringClass()->name == $classInfo->name) {
// $prop is public and is declared in class B
$propName = $prop->name;
$propValue = $prop->getValue($b);
// Since it is public, this will also work:
$propValue = $b->$propName
// $prop->getValue($b) will even work on protected or private properties
}
}
In PHP (Symfony 3);
I want to reference an existing object A in another object B which class extends the one of object A, like this:
class A {
private $property1;
private $property2;
public function __construct($p1,$p2){
$this->property1 = $p1;
$this->property2 = $p2;
}
}
class B extends A {
private $property3;
public function __construct($objectA,$p3){
$this = $objectA;
$this->property3 = $p3;
}
}
$a = new A('p1','p2');
$b = new B($a,'p3');
This does not work and throw the following error at the statement $this = $objectA:
Compile Error: Cannot re-assign $this
Which are documented and explain there and there. I am looking for a workaround.
You must call parent constructor and also make property1 and property2 visible in class B
<?php
class A {
private $property1;
private $property2;
public function __construct($p1,$p2){
$this->property1 = $p1;
$this->property2 = $p2;
}
public function getProperty1()
{
return $this->property1;
}
public function getProperty2()
{
return $this->property2;
}
}
class B extends A {
private $property3;
public function __construct($objectA,$p3){
parent::__construct($objectA->getProperty1(), $objectA->getProperty2());
$this->property3 = $p3;
}
}
$a = new A('p1','p2');
$b = new B($a,'p3');
See it live here: http://sandbox.onlinephpfunctions.com/code/705bf1827da2bdf10f8d961ee1cb6fbdd88bc663
As an alternative, you could use __call magic method to forward all cals to class A:
<?php
class A {
private $property1;
private $property2;
public function __construct($p1,$p2){
$this->property1 = $p1;
$this->property2 = $p2;
}
}
class B extends A {
private $property3;
private $a;
public function __construct($objectA,$p3){
$this->a = $objectA;
$this->property3 = $p3;
}
public function __call($name, $arguments)
{
return call_user_func_array(array($this->a, $name), $arguments);
}
}
$a = new A('p1','p2');
$b = new B($a,'p3');
Based on how to clone object to child class in php
Using get_object_vars on the parent object, you can get an array of properties keys and values. You can then loop through them and assign them to the child object:
<?php
class A {
protected $property1;
protected $property2;
public function __construct($p1,$p2){
$this->property1 = $p1;
$this->property2 = $p2;
}
}
class B extends A {
private $property3;
public function __construct($objectA,$p3){
//$this = $objectA;
$objValues = get_object_vars($objectA); // return array of object values
foreach($objValues AS $key=>$value)
{
$this->$key = $value;
}
$this->property3 = $p3;
echo $this->property1;
}
}
$a = new A('p1','p2');
$b = new B($a,'p3');
This does not work with private properties, they need to be at least of protected level.
I ended up managing it like that:
class B extends A{
public function __construct($objectA){
foreach($this as $k => $v){
if(isset($objectA->{$k})){
$this->{$k} = &$objectA->{$k};
}
}
}
}
Compare to #Antony answer, notice it has & in front of $objectA->{$k}: $this->{$k} = &$objectA->{$k};. As I understood it, with &, any change on $objectB of properties belonging to the extended class A applies to $objectA.
I am aware it is not perfect and quite hacky but it does the job I need. Thanks for the input given by everybody.
I'm stuck with a behaviour of PHP which I can't seem to understand.
class A {
private $v;
public function __construct(&$v)
{
$this->v = &$v;
}
public function setV($v) {
$this->v = $v;
}
public function getV() {
return $this->v;
}
}
class B extends A {
public function setV($v) {
$this->v = $v;
}
}
$v = '1';
$c = new A($v); // <= this will be replaced
echo $c->getV() . "\n";
$v = '2';
echo $c->getV() . "\n";
$c->setV('3');
echo $c->getV() . "\n";
echo $v . "\n";
Outputs
1
2
3
3
But when I replace the object creation with $c = new B($v); it outputs
1
2
2
2
I would expect the same output as before. Why is this? I use PHP 5.3 but probably update to try to fix this.
When a class extends another parent class it can only use public and protected variables and functions from the parent class..
So this will print the same result ;
<?php
class A {
private $v;
public function __construct(&$v)
{
$this->v = &$v;
}
public function setV($v) {
$this->v = $v;
}
public function getV() {
return $this->v;
}
}
class B extends A {
public function setV($v) {
parent::setV($v);
}
}
$v = '1';
$c = new B($v); // <= this will be replaced
echo $c->getV() . "\n";
$v = '2';
echo $c->getV() . "\n";
$c->setV('3');
echo $c->getV() . "\n";
echo $v . "\n";
?>
you use $c = new B($v) but class B has no constructor then why you pass the parameter $v. use parent's constructor and try :
class B extends A{
public function __construct($v)
{
parent::_construct($v)
}
}
then try with your replacement.
class ParentClass
{
public function list()
{
foreach ($this as $property => $value)
{
if (is_public($this->$property))
echo 'public: ';
else if (is_protected($this->$property))
echo 'protected: ';
echo "$property => $value" . PHP_EOL;
}
}
}
class ChildClass extends ParentClass
{
protected $Size = 4;
protected $Type = 4;
public $SubT = 1;
public $UVal = NULL;
}
$CC = new ChildClass;
$CC->list();
Using ReflectionProperty, it's possible. You could create a helper function if you want to make it less verbose:
<?php
function P($obj, $name)
{
return new ReflectionProperty($obj, $name);
}
class Foo
{
public $a;
public function __construct()
{
foreach (array_keys(get_object_vars($this)) as $name)
{
if (P($this, $name)->isPublic())
{
echo "Public\n";
}
}
}
}
new Foo();
?>