Welcome to the Treehouse Community

The Treehouse Community is a meeting place for developers, designers, and programmers of all backgrounds and skill levels to get support. Collaborate here on code errors or bugs that you need feedback on, or asking for an extra set of eyes on your latest project. Join thousands of Treehouse students and alumni in the community today. (Note: Only Treehouse students can comment or ask questions, but non-students are welcome to browse our conversations.)

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and a supportive community. Start your free trial today.

PHP

Andrew Shook
Andrew Shook
31,709 Points

Question about PHP syntax

So I am working on updating a PHP LESS compiler for a personal side project and I have run into something I just don't understand. This function call is inside an if statement:

echo var_dump($dirName);//null
if($this->keyword($dirName))

But $dirName isn't declared anywhere inside the file. So I looked looked at the function definition:

protected function keyword(&$word) {
        echo var_dump($word);//null
        if ($this->match('([\w_\-\*!"][\w\-_"]*)', $m)) {
            $word = $m[1]; // only place $word is defined?
            return true;
        }
        return false;
    }

And see that the function param is being passed by reference. So I searched for the variable declaration for $word, thinking it might be a global variable. The weird thing is, it isn't declared anywhere in the file either. Finally, I looked up the function definition for $this->match().

protected function match($regex, &$out, $eatWhitespace = null) {
        if ($eatWhitespace === null) $eatWhitespace = $this->eatWhiteDefault;
        echo var_dump($out);//null
        $r = '/'.$regex.($eatWhitespace && !$this->writeComments ? '\s*' : '').'/Ais';
        if (preg_match($r, $this->buffer, $out, null, $this->count)) {
            echo var_dump($out);// word
            $this->count += strlen($out[0]);
            if ($eatWhitespace && $this->writeComments) $this->whitespace();
            return true;
        }
        return false;
    }

Now match accepts $out, which is a global variable. So my first question is how can $dirName be passed to keyword() as $word and then to match() as $out if $dirName doesn't actually exist? Second question, how can $word be passed as by reference to the function that creates it without causing an error?

2 Answers

Chris Shaw
Chris Shaw
26,650 Points

Sorry I completely missed that the first time I read over your post, essentially the other good part of references is magic variables, I believe they have a proper name but I don't write as much PHP as I used to so my memory is hit and mess with the names, for example the below code will create an initial blank line because $magicVar doesn't exist but when the function is run $magicVar becomes a globally scoped variable which we can now use through-out our code.

<?php

function makeMagicHappen(&$magic) {
    $magic = 'something';
}

// Will be undefined so nothing will appear
echo ((string) isset($magicVar)) . '<br>';

makeMagicHappen($magicVar);

// Will be true and say '$magicVar = something'
echo ((string) isset($magicVar)) . ' -- $magicVar = ' . $magicVar;
Andrew Shook
Andrew Shook
31,709 Points

Yes that is exactly what I believed to be happening but I'd never seen it before and definitely had no idea what it was called (that made google almost useless).

Chris Shaw
Chris Shaw
26,650 Points

There are plenty of other goodies such as variable variables which if you visit http://www.php.net/manual/en/language.variables.variable.php look quite confusing but given the right course or tutorial make a lot of sense for when to use techniques such as these.

Andrew Shook
Andrew Shook
31,709 Points

Yeah, I've used variable variables before, but I don't think I've ever seen this little trick before. I've been working with PHP for 3 years and I'm shocked I've never come across this before. From what you told me, and a little experimentation, It looks like

this->keyword($dirName);

creates $dirName and assigns it the value of word. $word is defined as

$word = $m[1];

where $m is a variable created and defined by

$this->match("some regex", $m)'

Here $m is the word currently being parsed.

Seem very convoluted, but I think I understand whats going on. I'll keep searching google to see if I can find a proper name for this little phenomena. Randy Hoyt, I don't suppose you could help to point me in the right direction?

Chris Shaw
Chris Shaw
26,650 Points

The way I see this type of reference system is a lazy implementation of pointers which if you have ever messed around in C work in a similar way but in PHP's case it creates a memory chain to keep track of the reference you're working with at the time, once the function execution is complete PHP will then move on to assigning that reference value to whatever arguments have been defined as references and work out if they need a variable assigned to them.

I agree with you that the system is convoluted but considering PHP has no memory pointer implementation for security purposes it makes sense as to why the system is there.

Andrew Shook
Andrew Shook
31,709 Points

Yeah, it does remind me of C pointers. Although it has been many moons since I really used C. I have seen references done in php like this:

$a = "something";
$b = &$a;

But assigning a reference to an undefined variable in a function call throw me through a loop. Really weird!

Thanks for your help Chris.

Chris Shaw
Chris Shaw
26,650 Points

Glad to help, here's something that should blow your mind, it's quick, dirty and I wrote it in a couple of minutes but it proves a good point into how confusing all this really is.

<?php

$a      = 'hello';
$$a     = 'world';

function change(&$input) {
    $input = 'world';
}

echo '$a  = ' . $a . '<br>';
echo '$$a = ' . $$a . '<br><br>';

change($a);

echo $a . ' ' . $hello;
Chris Shaw
Chris Shaw
26,650 Points

Hi Andrew,

The & reference is a way of controlling an input variable and changing it's value while maintaining a separate return value for the function, the parameter $word is scoped to the function itself so you won't find any other reference to it apart from when you use it within your function code.

For example if I wanted to replace the value of a variable from an int value of 1 to 2 I can use a reference parameter and have it modify the value without ever using a return.

<?php

$myInt = 1;

function changeValue(&$input) {
    $input++;
}

// This will be '$myInt = 1'
echo '$myInt = ' . $myInt;

changeValue($myInt);

// This will be '$myInt = 2'
echo '<br>$myInt = ' . $myInt;

Hope that helps, you can learn more about references at http://www.php.net/manual/en/language.references.php.

Andrew Shook
Andrew Shook
31,709 Points

Chris, thanks for the quick reply. I understand passing values by reference, but what I don't understand is How $dirName, which is never declared in the file, can be passed.