Question

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"
    }
  }
}
*/
Was it helpful?

Solution

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.

OTHER TIPS

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;
}

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

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.

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.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top