PHP and returning null references (revisited)
Asked Answered
U

5

6

I've asked a question before, that essentially took the $null = null approach as a given, to returning a null reference in PHP.

After some cursory Googling, I didn't turn up much; leaving me to assume that the aforementioned approach is the best (read, only) way. However, it seems odd to me that PHP would (still) fail to support such functionality.

Anyways, if it's unclear; what (other, if any) ways exist to return null from a function by reference in PHP? I'm asking specifically about returning the null reference, not about the ternary operator issue that surfaced to explain my linked question.

For instance:

function &return_null(){
    return null;
}

$null_ref = return_null(); // fails

However:

function &return_null(){
    $null = null;
    return $null;
}

$null_ref = return_null(); // succeeds

I'm asking because I'm a bit OCD when creating reusable libraries; I really like clean code, with respect to however clean it can get in a given language. Using a placeholder $null = null makes my skin crawl, despite it achieving the desired functionality.


For the sake of completeness @yes123, here's the method snippet where this problem lives:

public static function &getByPath(Array &$array, $path, $delimiter){
    if(!is_array($path)){
        $path = explode($delimiter, $path);
    }
    $null = null;
    while(!empty($path)){
        $key = array_shift($path);
        if(!isset($array[$key])){
            return $null;
        }
        if(!empty($path) && !is_array($array[$key])){
            return $null;
        }
        $array = &$array[$key];
    }
    return $array;
}

There's also setByPath(), issetByPath(), and unsetByPath() in this ArrayPath class. I've aliased these static methods with the overloading magic. When an instance is constructed, an array is passed to the constructor (along with a delimiter), and the magic methods call the static ones using the referenced array of the instance. It's working pretty swell so far. In addition, I've written an alias function, array_path() that simply returns an instance. So for example, one can do:

$array = array(
    'foo' => array(
        'bar' => array(
            'hello' => 'world',
        ),
    ),
);

array_path($array, '/')->{'foo/bar/hello'} = 'universe';
var_dump($array);

/*
array(1) {
  ["foo"]=>
  array(1) {
    ["bar"]=>
    array(1) {
      ["hello"]=>
      string(8) "universe"
    }
  }
}
*/
Urethra answered 22/10, 2011 at 19:40 Comment(3)
you should make a real example of usage, because for sure there is a better way to do what you want without using referencesUntwine
+1 for (seemingly) unnecessary code making your skin crawl!Seumas
@yes123 - Unfortunately no, I make quite an effort to explore all possible means to accomplish a given task; in this instance that has once again piqued my curiosity on the issue, there is no logical option other than returning a reference, or null in some cases.Urethra
P
4

I'm not sure if "references" and "clean code" go together... :(

Anyway, references are not "pointers to" objects/values, rather, they are "pointers to" variables. Thus, only a variable is a suitable target. Said variable can "name" an object/value (read: be assigned a value), as demonstrated in the post. The post, however, does not return a "null reference" -- it returns a reference to a variable that "names" null.

(And then people wonder why I reject the terminology that a variable "stores a reference to an object" when dealing with high-level languages/concepts...)

Happy coding.

Panelist answered 22/10, 2011 at 20:57 Comment(1)
Thanks @pst - I guess the terminology I chose is incorrect in this context; "returning a null value (or value of null) by reference, in absence of an assigning name with which to reference" seemed like an invalid way of explaining it, but I suppose that answers the question itself; one cannot.Urethra
T
6

I'm also a bit anal about my code. There is no functional difference here but I think this looks and reads better. But that is just my personal preference.

function &getByPath(array &$array, $path, $delimiter = '/'){
    $result = NULL;

    // do work here and assign as ref to $result if we found something to return
    // if nothing is found that can be returned we will be returning a reference to a variable containing the value NULL

    return $result;
}
Thyestes answered 30/9, 2014 at 8:16 Comment(1)
It wouldn't feel un-easy about this, I needed to return a reference if element existed in array. I knew element might not even be there, so I check the return value for null before using it. I think this is a valid solution for a warning.Baram
P
4

I'm not sure if "references" and "clean code" go together... :(

Anyway, references are not "pointers to" objects/values, rather, they are "pointers to" variables. Thus, only a variable is a suitable target. Said variable can "name" an object/value (read: be assigned a value), as demonstrated in the post. The post, however, does not return a "null reference" -- it returns a reference to a variable that "names" null.

(And then people wonder why I reject the terminology that a variable "stores a reference to an object" when dealing with high-level languages/concepts...)

Happy coding.

Panelist answered 22/10, 2011 at 20:57 Comment(1)
Thanks @pst - I guess the terminology I chose is incorrect in this context; "returning a null value (or value of null) by reference, in absence of an assigning name with which to reference" seemed like an invalid way of explaining it, but I suppose that answers the question itself; one cannot.Urethra
M
3

As for returning by reference, it will not work the other way

You can only return variables by reference from a function - nothing else.

http://www.php.net/manual/en/language.references.return.php

You may want to rethink if reference is something you really need, especially that you are already passing $array as reference and returning it

Mersey answered 22/10, 2011 at 20:43 Comment(0)
P
1

I just do this (without initialising $null):

return $null;

It has the benefit of being like NikiC mentioned, where you can simply use isset($result) to determine if a result exists.

Pruter answered 28/12, 2014 at 15:40 Comment(0)
A
0

A solution for your particular problem is to generalize your code:

function &getByPath(array &$array, $path, $delimiter = '/'){
    if (!is_array($path)){
        $path = explode($delimiter, $path);
    }

    $current =& $array;
    foreach ($path as $part) {
        $current =& $current[$part];
    }

    return $current;
}

Now no magic null values are returned. Instead the function will return the element as the path specified, even if it did not yet exist (the path will be added to the array and initialized with null).

$element =& getByPath($array, 'hallo/world');
isset($element); // if the element didn't exist, this will return false
$element = 'hi'; // we can set the element, even if it did not exist

Oh, and by the way: There is no other way to return null by reference and I also don't see why you have a problem with that ;) Returning by reference means returning a variable and, well, null aint one.

Afternoon answered 22/10, 2011 at 20:26 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.