Kaspar
Kaspar

Reputation: 103

While loop: only Variables can be passed by reference error

I am running into a "Only variables should be passed by reference" error, because on the code I am using there is a line that does not put the explode() result into a variable. As required when using strict PHP standards.

However because the explode() function is used in a While loop I can't think of a appropriate solution.

My code looks like

    function user_exists($username) {
    rewind($this->fp);
        while(!feof($this->fp) && trim($lusername = array_shift(explode(":",$line = rtrim(fgets($this->fp)))))) {
            if($lusername == $username)
                return 1;
        }
    return 0;
}

Any suggestions on how to solve this?

Upvotes: 0

Views: 333

Answers (1)

Mike
Mike

Reputation: 24383

I think maybe you need to sit back and break your code apart a bit and take a look at what is happening.

First, condition is while !feof($this->fp)

From the manual:

feof — Tests for end-of-file on a file pointer

One thing you will notice here is that feof() is only a test which returns true or false. It does not advance the pointer position while looping over, so while using this function, somewhere else in your while loop there needs to be something that advances the pointer or else you will have an infinite loop.

Second condition is:

trim($lusername = array_shift(explode(":",$line = rtrim(fgets($this->fp)))))

First function from left to right is trim(), which returns a string. From our handy dandy comparison table we see that when doing if ((String) $var) it evaluates to false if and only if the string is empty ("") or the number zero as a string ("0"), otherwise it returns true. Personally I tend to really hate using if ((String) $var) (first because it's slightly unclear to newbies unless you know your comparison table well and second because 99% of the time people are doing that they are actually checking for string length, in which case I would want it to return true for the string "0"). So assuming that you don't need it to return false for "0" we could change this to strlen($var) > 0 and then manipulate the variable within the loop. That should greatly simplify things here.

So now we have:

while (!feof($this->fp) && strlen($var) > 0) { /*...*/ }

This will loop over until either we are at the end of the file or $var is an empty line. Everything else can be offloaded into the body of the while loop, so it is much easier to break apart.

So this is what we have now:

$line = rtrim(fgets($this->fp));
$lusername = array_shift(explode(":",$line)));

Uh-oh! There's that "nasty" error:

Strict Standards: Only variables should be passed by reference in /path/to/file.php on line x.

So we can see from here, the part producing the error is not explode(), but array_shift(). See also: Strict Standards: Only variables should be passed by reference

What this means is that since array_shift() modifies the array, it requires it to be by reference. Since you are not passing an actual variable but instead the result of a function, PHP is unable to modify it. It's similar to doing something like function($var) = 3;. Of course you can't do that. Instead you need to save the value to a temporary variable. So now we have:

$line = rtrim(fgets($this->fp));
$split = explode(":",$line);
$lusername = array_shift($split);

Woo hoo! No more warning message.

So putting this together, we now have:

while (!feof($this->fp) && strlen($lusername) > 0) {
    $line = rtrim(fgets($this->fp));
    $split = explode(":",$line);
    $lusername = array_shift($split);
    if($lusername == $username) {
        return 1;
    }
}

Also, as mentioned earlier, the fgets() will advance the pointer, which allows the !feof($this->fp) part in the while statement to vary.

Upvotes: 1

Related Questions