php reference versus value - php

class Test {
private $arr;
function __construct() {
$this->arr = array('test');
}
function getArr() {
return $this->arr;
}
}
$a = new Test();
$b = $a->getArr();
$b[0][0] = 'a';
$s = $a->getArr();
echo $s[0]
Why does this echo test instead of aest? Does PHP copy the array and the contents of the array when returning it? How do I get an array in which I can change the strings and have it reflected in the object?

By returning and assigning by reference:
class Test {
//...
function &getArr() {
return $this->arr;
}
}
$a = new Test();
$b =& $a->getArr();
$b[0][0] = 'a';
$s = $a->getArr();
echo $s[0];
Does PHP copy the array and the contents of the array when returning it?
From the point of view of the programmer, it works as if returning would copy the value, except when returning by reference. In terms of implementation, there are optimizations that avoid this happens, as long as it has no impact in the behavior of the script.

Related

How many instances of a class have been created

I want to know how many instances of a particular class are present in memory.
class Test
{
public function testFunction() { return 'Test'; }
}
I create some objects:
$test1 = new Test();
$test2 = new Test();
$test3 = new Test();
How can I count the number of Test objects?
You can implement this using a static variable in your class, which you keep updated via it's constructor and destructor. Here is how:
class MyClass {
public static $instanceCount = 0;
function __construct() {
self::$instanceCount++;
}
function __destruct() {
self::$instanceCount--;
}
}
// create 3 instances
$a = new MyClass();
$b = new MyClass();
$c = new MyClass();
echo MyClass::$instanceCount; // outputs: 3
// implicitly lose one instance (destructor is called)
$a = "test";
echo MyClass::$instanceCount; // outputs: 2
You can try get_defined_vars function
It returns an array with defined vars, then you'll need to loop through the array an count by class. To get the class of a given variable you can use get_class function.
Maybe something like this:
function countVars() {
$varsDefined = [];
foreach(get_defined_vars() as $v) {
$varClass = get_class($v);
if (!isset($varsDefined[$varClass])) $varsDefined[$varClass] = 0;
$varsDefined[$varClass]++;
}
return $varsDefined;
}
I couldĀ“t test the code so it could have some mistakes, but I think the idea is there :)
Hope it helps!

php class return; function return

object var $c->$var1 has been changed in class a;
var $new_var has not be changed in function d;
i was a litte puzzled.
my english is poor,can you understand me?
<?php
class a{
public function test () {
$b = new b;
$c = new c;
$b->test($c);
var_dump($c);
}
}
class b{
public function test($c) {
$c->var1 = 2;
return $c;
}
}
class c {
public $var1 = 1;
}
$a = new a;
$a->test();
function d($new_var) {
$new_var = 2;
return $new_var;
}
$new_var = 1;
d($new_var);
echo $new_var
You problem is that you have this function
function d($new_var) {
$new_var = 2;
return $new_var;
}
Where is it true that you maybe pass a different variable as parameter, but then you take that parameter and you decide to set it = 2 and then return it.
If you want to return what you passed you should change it in
function d($new_var) {
return $new_var;
}
Or if you want something similar to test function of class b try tgus
function d($new_var) {
$d->new_var = $new_var;
return $d;
}
So you can access to your $new_var in the returned objecd $d
You expect the following piece of code to change the value for $new_var from 1 to 2, right?
$new_var = 1;
d($new_var);
echo $new_var
Alas, that cannot be, because the returned value is never assigned back to the variable. To make sure the passed variable will retain its new value even outside the scope of the function it was passed to as an argument, you need to pass the variable as a reference instead of as a value, like this:
function d(&$new_var) {
$new_var = 2;
return $new_var;
}
Notice the ampersand (&) in front of the variable name in the signature of the function. This will cause the variable to be passed as a reference, so that it will retain any changes made to it inside the function.

Adding data to a reference to change the referenced array in PHP

I have built a function to retrieve the last specified key of an array, it references the array and displays it fine, however, when I try to add to the reference variable, it does not affect the referenced array.
Here is my code:
class test {
public function __construct() {
// For testing
$this->keys[] = 'key1';
$this->keys[] = 'key2';
$this->array['key1']['key2'] = 'Hello World';
}
protected function &getArray() {
$array = &$this->array;
foreach($this->keys as $key) {
$array = &$array[$key];
}
return $array;
}
function add() {
$tmpArray = $this->getArray();
print_r($tmpArray);
echo "<br>\n";
$tmpArray = 'Goodbye World';
print_r($tmpArray);
echo "<br>\n";
print_r($this->array);
}
}
$test = new test;
$test->add();
To sum it up, add() and __construct() are for testing. I am trying to add to $this->array with add(). However when I specify $tmpArray = 'Goodbye World' the referenced array $this->array['key1']['key2'] is still Hello World.
Could someone help point me in the right direction?
In order to return references in PHP, you need to use & twice, once in the definition and once more in assignment. You're missing the one in assignment:
$tmpArray = &$this->getArray();
See PHP: Returning References for details and please don't ask why as I'm incapable of generating rationale for PHP behaviour.

php overload equals-operator

In a PHP program I have an array of some custom objects, and I want to find if the array contains a certain object. Of course I can use array_search, but this checks if the objects are the same object, not if it has the same variables. So I want to be able to create my own compare function for the objects, which I can use with the array_search method (or something similar).
I want to be able to do something like this:
class foo
{
public $_a,$_b;
function __construct($a,$b)
{
$this->_a = $a;
$this->_b = $b;
}
function __equals($object)
{
return $this->_a == $object->_a;
}
}
$f1 = new foo(5,4);
$f2 = new foo(4,6);
$f3 = new foo(4,5);
$array = array($f1,$f2);
$idx = array_search($f3,$array); // return 0
Is something like this possible?
I know I can also create my own array_search method which uses a method from the class, but than I'd have to use 2 different search functions, one for the classes which do have their own compare function, and one for those which haven't.
Here's a neat little trick I recently found out:
class Foo {
public $a;
public $b;
public function __toString() {
return (string)$this->a;
}
public function __construct($a, $b) {
$this->a = $a;
$this->b = $b;
}
}
$a = new Foo(1, 'a');
$b = new Foo(2, 'b');
$c = new Foo(3, 'c');
$d = new Foo(2, 'd');
$array = array($a, $b);
$key = array_search($d, $array); // false
$key = array_search((string)$c, $array); // false
$key = array_search((string)$d, $array); // 1
This also works:
$is_equal = ((string)$d == $b); // true
When passed a string $needle, array_search will try to cast the objects contained in $haystack to string to compare them, by calling the __toString magic method if it exists, which in this case returns Foo::$a.
Usually its not. You may look at the PECL Operators-Extension, but thats really old.

Reference to static method in PHP?

In PHP, I am able to use a normal function as a variable without problem, but I haven't figured out how to use a static method. Am I just missing the right syntax, or is this not possible?
(EDIT: the first suggested answer does not seem to work. I've extended my example to show the errors returned.)
function foo1($a,$b) { return $a/$b; }
class Bar
{
static function foo2($a,$b) { return $a/$b; }
public function UseReferences()
{
// WORKS FINE:
$fn = foo1;
print $fn(1,1);
// WORKS FINE:
print self::foo2(2,1);
print Bar::foo2(3,1);
// DOES NOT WORK ... error: Undefined class constant 'foo2'
//$fn = self::foo2;
//print $fn(4,1);
// DOES NOT WORK ... error: Call to undefined function self::foo2()
//$fn = 'self::foo2';
//print $fn(5,1);
// DOES NOT WORK ... error: Call to undefined function Bar::foo2()
//$fn = 'Bar::foo2';
//print $fn(5,1);
}
}
$x = new Bar();
$x->UseReferences();
(I am using PHP v5.2.6 -- does the answer change depending on version too?)
PHP handles callbacks as strings, not function pointers. The reason your first test works is because the PHP interpreter assumes foo1 as a string. If you have E_NOTICE level error enabled, you should see proof of that.
"Use of undefined constant foo1 - assumed 'foo1'"
You can't call static methods this way, unfortunately. The scope (class) is relevant so you need to use call_user_func instead.
<?php
function foo1($a,$b) { return $a/$b; }
class Bar
{
public static function foo2($a,$b) { return $a/$b; }
public function UseReferences()
{
$fn = 'foo1';
echo $fn(6,3);
$fn = array( 'self', 'foo2' );
print call_user_func( $fn, 6, 2 );
}
}
$b = new Bar;
$b->UseReferences();
In php 5.2, you can use a variable as the method name in a static call, but to use a variable as the class name, you'll have to use callbacks as described by BaileyP.
However, from php 5.3, you can use a variable as the class name in a static call. So:
class Bar
{
public static function foo2($a,$b) { return $a/$b; }
public function UseReferences()
{
$method = 'foo2';
print Bar::$method(6,2); // works in php 5.2.6
$class = 'Bar';
print $class::$method(6,2); // works in php 5.3
}
}
$b = new Bar;
$b->UseReferences();
?>
You could use the full name of static method, including the namespace.
<?php
function foo($method)
{
return $method('argument');
}
foo('YourClass::staticMethod');
foo('Namespace\YourClass::staticMethod');
The name array array('YourClass', 'staticMethod') is equal to it. But I think the string may be more clear for reading.
In PHP 5.3.0, you could also do the following:
<?php
class Foo {
static function Bar($a, $b) {
if ($a == $b)
return 0;
return ($a < $b) ? -1 : 1;
}
function RBar($a, $b) {
if ($a == $b)
return 0;
return ($a < $b) ? 1 : -1;
}
}
$vals = array(3,2,6,4,1);
$cmpFunc = array('Foo', 'Bar');
usort($vals, $cmpFunc);
// This would also work:
$fooInstance = new Foo();
$cmpFunc = array('fooInstance', 'RBar');
// Or
// $cmpFunc = array('fooInstance', 'Bar');
usort($vals, $cmpFunc);
?>
Coming from a javascript background and being spoiled by it, I just coded this:
function staticFunctionReference($name)
{
return function() use ($name)
{
$className = strstr($name, '::', true);
if (class_exists(__NAMESPACE__."\\$className")) $name = __NAMESPACE__."\\$name";
return call_user_func_array($name, func_get_args());
};
}
To use it:
$foo = staticFunctionReference('Foo::bar');
$foo('some', 'parameters');
It's a function that returns a function that calls the function you wanted to call. Sounds fancy but as you can see in practice it's piece of cake.
Works with namespaces and the returned function should work just like the static method - parameters work the same.
This seems to work for me:
<?php
class Foo{
static function Calc($x,$y){
return $x + $y;
}
public function Test(){
$z = self::Calc(3,4);
echo("z = ".$z);
}
}
$foo = new Foo();
$foo->Test();
?>
In addition to what was said you can also use PHP's reflection capabilities:
class Bar {
public static function foo($foo, $bar) {
return $foo . ' ' . $bar;
}
public function useReferences () {
$method = new ReflectionMethod($this, 'foo');
// Note NULL as the first argument for a static call
$result = $method->invoke(NULL, '123', 'xyz');
}
}
"A member or method declared with static can not be accessed with a variable that is an instance of the object and cannot be re-defined in an extending class"
(http://theserverpages.com/php/manual/en/language.oop5.static.php)

Categories