PHP returning references - php

I have read the section of returning references in PHP by putting the ampersand in both the function definition and variable assignment. But, I have yet to find examples of "returning references" in php code that does not relate to Object Oriented Programming. Can anyone provide a use for this and an example?

Let me start, from a very simplified example,
class Test {
//Public intentionally
//Because we are going to access it directly later
//in order to see if it's changed
public $property = 'test';
/**
* Look carefully at getPropReference() title
* we have an ampersand there, that is we're indicating
* that we're returning a reference to the class property
*
* #return string A reference to $property
*/
public function &getPropReference()
{
return $this->property;
}
}
$test = new Test();
//IMPORTANT!! Assign to $_foo a reference, not a copy!
//Otherwise, it does not make sense at all
$_foo =& $test->getPropReference();
//Now when you change a $_foo the property of an $test object would be changed as well
$_foo = "another string";
// As you can see the public property of the class
// has been changed as well
var_dump($test->property); // Outputs: string(14) "another string"
$_foo = "yet another string";
var_dump($test->property); //Outputs "yet another string"

Update: This answer relates to passing by reference, not returning by reference. Retained for it's information value.
Read this:
http://php.net/manual/en/language.references.pass.php
Then take a look at this example:
<?php
function AddTimestamp(&$mytimes)
{
$mytimes[] = time();
}
$times = array();
AddTimestamp($times);
AddTimestamp($times);
AddTimestamp($times);
// Result is an array with 3 timestamps.
Can this be better implemented using object oriented techniques? Perhaps, but from time to time there is a need/reason to modify an existing value-based data structure or variable.
Consider this:
function ValidateString(&$input, &$ErrorList)
{
$input = trim($input);
if(strlen($input) < 1 || strlen($input) > 10)
{
$ErrorList[] = 'Input must be between 1 and 10 characters.';
return False;
}
}
$Err = array();
$Name = ' Jason ';
ValidateString($Name, $Err);
// At this point, $Name is trimmed. If there was an error, $Err has the message.
So, depending on your needs, there are still times to pass by reference in PHP. Objects are always passed by reference, so anytime you encapsulate your data in an object, it automatically becomes a reference.

Related

Is there ever a need to use ampersand in front of an object?

Since objects are passed by reference by default now, is there maybe some special case when &$obj would make sense?
Objects use a different reference mechanism. &$object is more a reference of a reference. You can't really compare them both.
See Objects and references:
A PHP reference is an alias, which allows two different variables to write to the same value. As of PHP 5, an object variable doesn't contain the object itself as value anymore. It only contains an object identifier which allows object accessors to find the actual object. When an object is sent by argument, returned or assigned to another variable, the different variables are not aliases: they hold a copy of the identifier, which points to the same object.
&$object is something else than $object. I'll give you an example:
foreach ($objects as $object) {
if ($cond) {
$object = new Object(); // This won't affect $objects
}
}
foreach ($objects as &$object) {
if ($cond) {
$object = new Object(); // This will affect $objects
}
}
I won't answer the question if it makes sense, or if there is a need. These are opinion based questions. You can definitely live without the & reference on objects, as you could without objects at all. The existence of two mechanisms is a consequence of PHP's backward compatibility.
There are situations where you add & in front of function name, to return any value as a reference.
To call those function we need to add & in front of object.
If we add & in front of object, then it will return value as reference otherwise it will only return a copy of that variable.
class Fruit() {
protected $intOrderNum = 10;
public function &getOrderNum() {
return $this->intOrderNum;
}
}
class Fruitbox() {
public function TestFruit() {
$objFruit = new Fruit();
echo "Check fruit order num : " . $objFruit->getOrderNum(); // 10
$intOrderNumber = $objFruit->getOrderNum();
$intOrderNumber++;
echo "Check fruit order num : " . $objFruit->getOrderNum(); // 10
$intOrderNumber = &$objFruit->getOrderNum();
$intOrderNumber++;
echo "Check fruit order num : " . $objFruit->getOrderNum(); // 11
}
}

PHP Object References?

I've read up about PHP variable references but I'm not 100% and was hoping someone could help.
If I have a class like the following:
class Item
{
public $value;
}
I then have an array of those items in a variable - lets call that $items. All I did was new Item()...and $items[] = $newItem;.
Now, I want to populate another array but it filters the original array based on its value. So like the following:
foreach($items as $key => $value)
{
$filteredItems[] = &value;
}
Now, I have ANOTHER variable that iterates over that filtered list and does something like so:
$theItem = $filteredItems[10];
$theItem->value = 100;
Now this is where I'm confused. Do I need to set $theItem to &filteredItems[10]; (reference) or will it just know that the value in the array is a reference type and $theItem also becomes a reference to that same item? I'm after that last set of $theItem->value = 100; changes the very original object stored in the $items list.
In PHP 5 objects are always passed around by their "handle" for lack of better word. This means if you do this:
$a = new Item();
$a->value = 1;
$b = $a;
$b->value++;
echo $a->value;
The value of 2 is echoed. Why? Because the handle of the object is copied from $a to $b and they both point to the same object. This isn't a reference in terms of using &, but behaves similarly enough to the point that people generally call it the same thing... even though it's not.
So you do not need any use of references in your code. Usually in PHP, you never need to use references when using objects.
With respect to objects, you really only notice references if you do this (assign a new value to the variable itself):
function foo(Item &$a)
{
$a = null;
}
$b = new Item();
foo($b);
var_dump($b);
This results in NULL, which wouldn't happen without a reference. But again, this is not typical usage, so you can really forget about using references with objects.
(And of course the use of a function isn't necessary here to illustrate the point, but that's the most typical place you'll see them in the "real world.")
It's like this:
foreach($items as $key => &$value) {
$filteredItems[] = $value;
}
The point where you give the original instance into a different scope is where you put the &.
Same is for functions:
function myFunction(&$variable) { }
Example:
<?php
class test {
public $testVar;
public function __construct() {
$this->testVar = "1";
}
}
function changeByReference(&$obj) {
$obj->testVar = "2";
}
$instance = new test();
// Prints 1
echo $instance->testVar, PHP_EOL;
changeByReference($instance);
// Prints 2
echo $instance->testVar, PHP_EOL;
Read more about it here: http://php.net/manual/en/language.oop5.references.php
If you want to copy an instance, use clone - php.net/clone
The easiest way to get it is when you know the difference between these: class, object and instance. (I'd explain it more at this point but it would only confuse you more because my english is not accurate enough for now to explain the details enough.)

Get variable name from within the called function

Can I do this, maybe using ReflectionClass ?
myprintr($some_object);
function myprintr(){
foreach(func_get_args() as $key => $arg){
// here I want to get the name of the passed variable, "some_object"
// $key seems to be numeric...
}
}
You cannot get the name of the "variable", as there is no variable.
eg:
myprintr("test");
myprintr(myotherfun());
Note: I'm not sure what you are trying to do, but I just feels terrifyingly wrong.. the whole point of functions and objects is to create barriers, and it shouldn't matter what is in the caller's context..
If the user passes an object to myprintr(), then you can use
if (is_object($arg)) {
$className = get_class($arg);
}
to get the name of the object type that has been passed, which you can then feed to reflection
but the reflection constructor will accept either a class name or an object as an argument, so you don't even need the class name to instantiate a reflection class
EDIT
Just for the sake of playing a bit with this concept (and not creating any dependency on globals), or on whether the arguments are variables, values returned from functions, strings, etc:
class Test{};
function myTest() {
$some_object = new Test();
myprintr($some_object);
}
function myprintr(){
$callStack = debug_backtrace();
$calledAt = $callStack[0];
$callingFile = file($calledAt['file'],FILE_IGNORE_NEW_LINES);
$callingLine = $callingFile[$calledAt['line']-1];
$callingLine = substr($callingLine,strpos($callingLine,__METHOD__));
$calledWithArgNames = trim(substr($matches[0],1,-1));
var_dump($calledWithArgNames);
$args = func_get_args();
foreach($args as $arg) {
var_dump($arg);
}
}
myTest();
$some_object = new Test();
$some_other_object = &$some_object;
$t = 2;
$gazebo = "summer house";
$visigoth = pi() / 2; myprintr($some_other_object,pi(), atan2(pi(),$t), $visigoth, "Hello $t World", $gazebo); $t = log($t/$visigoth);
This retrieves all the arguments passed by the calling function in $calledWithArgNames, so for the first call you have:
'$some_object'
and for the second call:
'$some_other_object,pi(), atan2(pi(),$t), $visigoth, "Hello $t World", $gazebo'
This still requires splitting down into the individual arguments (a preg_split on commas, except where they're inside braces), but is certainly a step closer to what you're actually asking for.
You can't access argument names that don't exist: myprintr doesn't specify any variable names, and func_get_args() will only ever return a numerically indexed array.
I suppose you could add docblock comments and access them with reflection, but this seems like an extraordinary amount of overhead for functionality that you most likely don't need anyway. Using reflection on the function's arguments itself won't do anything for you because, again, you didn't specify any arguments in the function's argument signature.
PHP function arguments are ordered. They aren't something you can reference like an associative array. If you want access to "associative" type key names for a function or method's arguments, you'll have to specify an array argument and pass a value with the associative keys you want, like this:
myfunc(array $args=[])
{
$key1 = isset($args['key1']) ? $args['key1'] : NULL;
$key2 = isset($args['key2']) ? $args['key2'] : NULL;
}
If it is an object you can use func_get_args() and spl_object_hash() to identify the object and then search it in $GLOBALS. There you find the name.
class Test{};
$some_object = new Test();
myprintr($some_object);
function myprintr(){
$args = func_get_args();
$id = spl_object_hash($args[0]);
foreach($GLOBALS as $name => $value)
{
if (is_object($value) && spl_object_hash($value) == $id) echo $name;
}
}
http://codepad.org/gLAmI511

Function on objects that return specific values when the object is cast

First of all, I apologize that this question is so vague. I can't remember what this is called, or how they work, so it's very difficult to start searching or formulate a good title.
I have two questions wrapped into one:
First:
How are objects converted to other types internally? What is this called?
Example:
$Obj{
$value = 1;
$other = 2;
$more = 3;
}
$myObj = (string)$Obj;
print $myObj; // prints "1, 2, 3" or something like that
Second:
Can this method be used in math? Is there some override function that recognizes when an Object is being used in math?
Example:
$Obj{
$value = 1;
$other = 2;
$more = 3;
}
$result = 4 / $Obj;
print $result; // prints ".66666667" or something similar (sum of all properties)
Update:
I think it might have something to do with serialize(), but I know I've heard of a case where this is done "automatically" without having to call serialize() and it's done in a way that doesn't actually serialize the whole object, it just converts it to a useable value, like my above examples.
Final:
Thanks for #trey for being right about it being casting and to #webbiedave for pointing me to the magic method __toString.
It is casting as you can define the magic method __toString to allow the object to be cast to a string as desired, which will then allow PHP to cast it to an int or float in math.
Take the following example:
class A
{
public $value = 1;
public $other = 2;
public $more = 3;
public function __toString()
{
return (string)($this->value + $this->other + $this->more);
}
}
$obj = new A();
echo 4 / (string)$obj; // outputs 0.66666666666667
It's called type casting when you change an object to a different data type, as for the second part, I'm not entirely sure I understand you, are you trying to type cast during a math function?
it sounds like this may be more along the lines of what you're looking for:
class User
{
public $first_name='John';
public $last_name='Smith';
public function __toString()
{
return "User [first='$this->first_name', last='$this->last_name']";
}
}
$user=new User;
print '<span>'.$user.'</span>';
but I'm unable to find documentation about how to make this work when the object is converted to an interger... I'll update if I do

Php string is a value type?

Why php's string is a value type? It is copied all over the place every time the argument is passed to a function, every time the assignment is made, every concatenation causes string to be copied. My .NET experience tells me that it seems inefficient and forces me to use references almost everywhere. Consider the following alternatives:
Alternative 1
// This implementation hurts performance
class X {
public $str;
function __construct($str) { // string copied during argument pass
$this->$str = $str; // string copied here during assignment
}
}
Alternative 2
// This implementation hurts security
class Y {
public $str;
function __construct(&$str) {
$this->$str = &$str;
}
}
// because
$var = 'var';
$y = new Y($var);
$var[0] = 'Y';
echo $y->var; // shows 'Yar'
Alternative 3
// This implementation is a potential solution, the callee decides
// whether to pass the argument by reference or by value, but
// unfortunately it is considered 'deprecated'
class Z {
public $str;
function __construct($str) {
$this->$str = &$str;
}
}
// but
$var = 'var';
$z = new Z(&$var); // warning jumps out here
$var[0] = 'Z';
echo $y->var; // shows 'Zar'
The question: What pain should I choose Performance / Security / Deprecation
PHP handle's it's variables pretty reasonably. Internally, PHP uses a copy-on-modification system.
That is to say that those values will be assigned by reference until one of them is changed, in which case it will get a new slot in memory for the new value.
Passing vars by reference is going to hurt performance.
Your example #1 is the best performance and best way to go about it.
class X {
public $str;
function __construct($str) {
$this->str = $str;
}
}

Categories