Attribute reference does not work with inheritence - php

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.

Related

Copy a class into another

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.

why php_pthreads canot use for to created multithreading ? PHP 5.3 with php_pthreads extendsion

<?php
class Timer {
static private $s;
function __construct()
{
self::$s = self::getmicrotime();
}
static public function Start()
{
self::$s = self::getmicrotime();
}
static public function Fetch($decimalPlaces = 6)
{
return number_format((self::getmicrotime() - self::$s), $decimalPlaces);
}
static public function getmicrotime()
{
return array_sum(explode(' ', microtime()));
}
}
class T extends Thread {
public function run() {
test();
}
}
function test()
{
$n = 0;
for($i=1;$i<9999999;$i++)
{
$n+=$i;
}
echo '#';
}
//+++++++++++++++++++++++START DEMO ++++++++++++++++++++++++++
Timer::Start();
//DEMO1,TIME:3.679208 second(s).
$ts = array();
while (count($ts)<10) {
$t = new T();
$t->start();
$ts[]=$t;
}
$ts = array();
//DEMO2,TIME:6.876037 second(s).
/* for($k=0;$k<10;$k++)
{
$t = new T();
$t->start();
} */
echo '<br />Processed in '.Timer::Fetch().' second(s).';
?>
I am reading http://pthreads.org/ on the topic of pthreads and i have this questions,I want to test php multithreading ,but when i use for to create multithreading,but it is not the result I want.
In fact the DEMO1 is correct.
But why the second DEMO elapsed_time 6.876037 second ?
DEMO2 why canot use for to create multithreading ?

Getting back information added with multiple calls to a function

I want to have a function and then use it multiple times with different parameters.
For example:
<?php
class Test {
var $test;
public function func($val) {
$this->test = $val;
}
public function buildFunc() {
if(!empty($this->test)) {
$ret = $this->test;
}
return $ret;
}
}
?>
Then on calling page:
$test = new Test;
$test->func("test1");
$test->func("test2");
echo $test->buildFunc();
Then it prints test2 on the screen. And I want it to print out both of them.
Either create 2 instances of your object;
$test1 = new Test;
$test1->func("test1");
$test2 = new Test;
$test2->func("test2");
echo $test1->buildFunc();
echo $test2->buildFunc();
Or make test an array;
class Test {
var $test = array();
public function func($val) {
$this->test[] = $val;
}
public function buildFunc() {
return print_r($this->test, true);
}
}
May be you mean that you want to store all values? Then use an array:
public function func($val) {
$this->test[] = $val;
}
public function buildFunc() {
return $this->test
}
And then work with the result as with an array.
Well.. your code does exactly what are you telling it to do. Consider situation when you have no OOP:
$str = 'test 1';
$str = 'test 2';
echo $str; //prints test 2
So you need to echo them separately as if it wont be an OOP situation.
$test = new Test;
$test->func("test1");
echo $test->buildFunc();
$test->func("test2");
echo $test->buildFunc();
When calling the method create 2 instances of the test object.
$test = new Test;
$test->func("test1");
echo $test->buildFunc();
$test2 = new Test;
$test2->func("test2");
echo $test2->buildFunc();
if you dont want to create 2 instances you have to make a array instead.
How about create a constructor and initialize the value of test and concat the second value.
<?php
class Test {
var $test;
public function __construct($init){
$this->test = $init;
}
public function func($val) {
$this->test .= $val;
return $this;
}
public function buildFunc() {
if(!empty($this->test)) {
$ret = $this->test;
}
return $ret;
}
}
$test = new Test("test1");
$test->func("test2");
echo $test->buildFunc();
?>
When you say both do you mean something like
test1test2
or do you want
test1
test2
For the first option you can just append the string:
<?php
class Test {
var $test;
public function func($val) {
$this->test = $test . $val; <-- add val to the end
}
public function buildFunc() {
if(!empty($this->test)) {
$ret = $this->test;
}
return $ret;
}
}
?>
For the second:
<?php
class Test {
var $test = array();
public function func($val) {
$this->test[] = $val; <-- add val to
}
public function buildFunc() {
if(!empty($this->test)) {
foreach($test as $item){
echo $item . "<br/>";
}
}
}
}
?>
Push the variables to an array
<?php
class Test {
var $test;
public function __construct(){
$this->test=array();//Declare $test as an array
}
public function func($val) {
$this->test[]=$val;//Push to array
}
public function buildFunc() {
if(!empty($this->test)) {
$ret = implode(",",$this->test);
}
return $ret;
}
}
?>

PHP Class Parent Instance (Singleton)

The scenario is this
class a
{
public $val;
}
class b extends a
{
}
class c extends b
{
}
$one = new b();
$one->val = "a value";
$other = new c();
echo $other->val;
// wanted 'a value', got ''
So the result i need here is: "a value", but of course is blank.
What i need is that the 'a' class to always be used as an instance in 'b'. So whenever i use a class that extends the 'b', the parent 'a' class to be inhereted as an instance.
If you read the php manual on the static keyword it gives an example of exactly what you are trying to do. You can read about it here: http://www.php.net/manual/en/language.oop5.static.php
Here is the example code they use.
<?php
class Foo
{
public static $my_static = 'foo';
public function staticValue() {
return self::$my_static;
}
}
class Bar extends Foo
{
public function fooStatic() {
return parent::$my_static;
}
}
print Foo::$my_static . "\n";
$foo = new Foo();
print $foo->staticValue() . "\n";
print $foo->my_static . "\n"; // Undefined "Property" my_static
print $foo::$my_static . "\n";
$classname = 'Foo';
print $classname::$my_static . "\n"; // As of PHP 5.3.0
print Bar::$my_static . "\n";
$bar = new Bar();
print $bar->fooStatic() . "\n";
?>
Since $other = new c(); is actually creating a new instance, it is not possible.
but if you declare val as Static member, you will have the result that you want.
<?
class a
{
public static $val;
}
class b extends a
{
}
class c extends b
{
}
$one = new b();
a::$val = "a value";
echo c::$val;
Here is how to do it without Inheritance:
class A
{
public $foo;
}
class B {
public function __construct(A $a)
{
$this->a = $a;
}
}
class C {
public function __construct(A $a)
{
$this->a = $a;
}
}
$a = new A;
$b = new B($a);
$c = new C($a);
$b->a->val = 'one value';
echo $c->a->val;
If you dont like having to fetch $a first to get to val, you could assign by reference
class A
{
public $foo;
}
class B {
public function __construct(A $a)
{
$this->val = &$a->val;
}
}
class C {
public function __construct(A $a)
{
$this->val = &$a->val;
}
}
$a = new A;
$b = new B($a);
$c = new C($a);
$b->val = 'one value';
echo $c->val;
Though personally I find the first approach more maintainable and clear.

Find the property's scope within class

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

Categories