Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to determine if a pass-by-reference variable is set?

Tags:

php

For an arbitrary function declared as follows:

function foo($first, &$second = null) {
    // if ($second is assigned) {
    //     Work with $second
    // }
}

How does one determine if $second is indeed assigned to a variable at call time, eg.:

foo('hello', $second);

vs

foo('hello'); // Notice &$second is unassigned

Tried isset(), is_null() but they don't seem to work.

Update:

Created a test script here here

like image 350
uzyn Avatar asked Oct 28 '12 16:10

uzyn


People also ask

How do we decide whether a variable should be passed by value or by reference?

Use pass by value when when you are only "using" the parameter for some computation, not changing it for the client program. In pass by reference (also called pass by address), a copy of the address of the actual parameter is stored.

How do you identify a reference variable?

A reference variable is a variable that points to an object of a given class, letting you access the value of an object. An object is a compound data structure that holds values that you can manipulate. A reference variable does not store its own values.

What happens if a variable is passed by reference?

Passing by reference means that the memory address of the variable (a pointer to the memory location) is passed to the function. This is unlike passing by value, where the value of a variable is passed on.

Are sets passed by reference in C++?

C++ makes both pass by value and pass by reference paradigms possible. You can find two example usages below. Arrays are special constructs, when you pass an array as parameter, a pointer to the address of the first element is passed as value with the type of element in the array.


4 Answers

It's my understanding that you wish to implement a function that implements something like preg_match, whereby the third argument gets populated with the memory patterns if passed.

Internally, PHP functions use a function called zend_parse_parameters(); it accepts a format string and a variable number of arguments that will be populated with the meta data of the call parameters. If a parameter is not passed (e.g. when it's optional), the meta data is not available and thus is easy to detect.

Coming back to PHP itself, unfortunately there's no such thing as func_arg_used($var) that will tell you if $var was passed as a function argument; perhaps this would be an interesting contribution to the language, but until then you'll have to settle for something more ancient :)

if (func_num_args() > 1) {
    // $second was passed and can be used to populate
}

You may have to be careful when changing the signature of the function, especially when you add parameters in front of $second; however, naturally this shouldn't happen often because it would most definitely break dependent functions. Adding more arguments at the end has no effect on above code.

There are two ways you can go with this:

  1. ReflectionFunction - the shiny new toy of developers, it allows you to introspect your function and determine whether the signature changed from when it was created. Use it sparingly though, introspection is not cheap, especially considering the alternativey.

  2. The humble code comment - the much understated form of code policing; a simple line that says // IMPORTANT - don't add arguments before $second

like image 107
Ja͢ck Avatar answered Oct 12 '22 01:10

Ja͢ck


You can't (as far as I know) tell the difference between NULL and Undefined using isset. You could set default value of $second to some random value that will never be used otherwise.

define('UNDEFINED', -19181818);

function foo($first, &$second = UNDEFINED) 
{
 if($second==UNDEFINED)
 {
  etc..
 }
}
like image 30
Niall Avatar answered Oct 12 '22 02:10

Niall


Works for me:

<?php

function bool_str($b)
{
    return ($b ? "true" : "false");
}

function foo($first, &$second = null)
{
    echo bool_str(isset($first)) . " " . bool_str(isset($second)) . " " .
         bool_str(is_null($first)) . " " . bool_str(is_null($second)) . "\n";
}

$a = 1;
$b = 2;

foo($a, $b);
foo($a);

?>

Output:

true true false false
true false false true
     ^^^^^       ^^^^

Which is precisely what I would expect, i.e. you can use both isset and is_null here.

like image 37
Lightness Races in Orbit Avatar answered Oct 12 '22 02:10

Lightness Races in Orbit


I think the suggestion by Jack to use func_num_args() is excellent.

function foo($first, &$second = null) {
    if (func_num_args() > 1) {
        //$second MUST be assigned
    }
}

This properly detects when $second references a variable which exists in the calling scopes' symbol table, yet it has a variable value of null.

$second = null;
foo('hello', $second);
like image 31
goat Avatar answered Oct 12 '22 01:10

goat