2

So today I attempted something which I thought would be possible, but apparently it isn't.

PHP version: 5.6

Take a look at this snippet of code:

$m = 1;
while ($m <= 12) {
    if (! isset($$dataRef[$m])) {
        echo '0,';
    } else {
        echo $$dataRef[$m] . ',';
    }
    $m++;
}

Where $$dataRef is an numerically indexed array, which is by month (e.g. [1 => 12345.67])

What the if statement does is checks if the month number is defined, if it isn't, echo 0, otherwise do the value.

The above snippet results in the if statement not being executed. And I can't figure out why?

However, if the array is then assigned to a "normal" variable, the code works perfectly:

$m = 1;
$data = $$dataRef;
while ($m <= 12) {
    if (! isset($data[$m])) {
        echo '0,';
    } else {
        echo $data[$m] . ',';
    }
    $m++;
}

Anyone able to explain this?

Matt Cavanagh
  • 518
  • 5
  • 19
  • A blank page often means your script is throwing an error but PHP is configured to hide it from you. You need to fix it ASAP because coding without the aid of error messages is hard. As quick start, you can set the `error_reporting` and `display_errors` directives in your computer's system-wide `php.ini` file ([details here](http://stackoverflow.com/a/5680885/13508)). Errors thumb rule: show in development, log in production. – Álvaro González Feb 01 '17 at 15:42
  • Thanks for your response @ÁlvaroGonzález but I've got my dev environment set up correctly, it's set to E_ALL, which all errors and any infos should appear. The first set of code simply was not spitting anything out whatsoever. – Matt Cavanagh Feb 01 '17 at 15:43
  • 2
    you can concat evaluated vars like this `${$dataRef[$m]}` – Daniel W. Feb 01 '17 at 15:44
  • Then it's a webserver misconfiguration error. Btw you should never use `$$`, ever. Really. It makes your code a plate of spaghetti. – Rápli András Feb 01 '17 at 15:44
  • @DanFromGermany See this is where things get a bit odd, if I did `echo $$dataRef[12]` directly it would work, however it seems that as soon as another variable is involved (for the key ref) then it doesn't like doing that. Would using concat do the trick with that? – Matt Cavanagh Feb 01 '17 at 15:46
  • @RápliAndrás In most scenarios I would agree `$$` is the spawn of all evil, but in this case it was quite a challenge to re-write all the entire code just for a small bugfix, so I chose to keep with the current structure. – Matt Cavanagh Feb 01 '17 at 15:47
  • Like @RápliAndrás said, it's generally a bad idea to combine variables to a new variable. Other than that, play arround with `{ }` – Daniel W. Feb 01 '17 at 15:47
  • Hmm, I guess what I'm not understanding then is why this wouldn't work? Surely `$$` should be treated like any other variable? I understand that it's not great to use them, but I also don't get why it wouldn't actually work? That's what I'm trying to understand here. – Matt Cavanagh Feb 01 '17 at 15:48
  • 1
    Because you don't use `${$}` to properly evaluate the variables from inner to outer.. How should PHP know which of those two you do mean? `${$dataRef[$m]}` vs `${$dataRef}[$m]` – Daniel W. Feb 01 '17 at 15:51
  • Ahh good point, so perhaps it was accessing the string (e.g. `$dataRef = 'y2015'`) and no the the actual variable / array it's referencing. That makes sense. – Matt Cavanagh Feb 01 '17 at 15:53

3 Answers3

2

Your code carefully omits the relevant variable declarations. I'm guessing that missing parts may look like this:

$abc = array(
    1 => 12345.67,
    2 => 876.54,
);
$dataRef = 'abc';
var_dump($$dataRef[0], $$dataRef[1], $$dataRef[2]);

... and the notices give you a clue:

PHP Notice:  Undefined variable: a
PHP Notice:  Undefined variable: b
PHP Notice:  Undefined variable: c

In other words, you are not using [] as array operator. You are using it as string offset operator. You want this instead:

var_dump(${$dataRef}[1], ${$dataRef}[2]);
float(12345.67)
float(876.54)
Álvaro González
  • 142,137
  • 41
  • 261
  • 360
  • Yup that's pretty much what I've just realized as I wrote my own answer, the indexes were basically being referenced as an index of the string, not the array it's meant to look at. Thanks for the help! – Matt Cavanagh Feb 01 '17 at 15:58
  • Marked your answer as the correct one as it offers vastly more detail than mine. – Matt Cavanagh Feb 01 '17 at 15:58
  • 1
    Looking into it further and running it on a script by itself, I was indeed getting notices. I think my application was swallowing them. Think next time I debug something like this I rip it out and put it in it's own script :P – Matt Cavanagh Feb 01 '17 at 15:59
  • Notice in particular was `Notice: Uninitialized string offset: 5 in /vagrant/varvar.php on line 9`, were you getting a similar notice? – Matt Cavanagh Feb 01 '17 at 16:00
  • I discarded my first tests but I think those were. – Álvaro González Feb 01 '17 at 16:01
0

Variables starting with a numeral are not valid to begin with. So $1...$12 and beyond can't be used.

http://php.net/manual/en/language.variables.basics.php

mike.k
  • 3,277
  • 1
  • 12
  • 18
0

It appears to do with how the variable's are parsed, and if operations upon them.

The code below works, notice the concat brackets:

$m = 1;
while ($m <= 12) {
    if (! isset(${$dataRef}[$m])) {
        echo '0,';
    } else {
        echo ${$dataRef}[$m] . ',';
    }
    $m++;
}

Basically meaning "inject this string into the var name then use the result's index".

Of course, using var vars should be avoided at all costs in all honesty.

Matt Cavanagh
  • 518
  • 5
  • 19