Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

Kerren's avatar

Detecting Variable Scope Issues

Hi guys,

I recently hit a variable scoping issue and I'd really like to see what you guys would do to pick it up before runtime? Let's assume we have a variable $details from before.

$ids = [];
foreach ($details as $detail) {
    if (is_array($detail)) {
        $id = $detail['id'];
        $ids[] = $id;
    } else {
        $ids[] = $id;
    }
}

I know this looks really simple, there was a lot more around it that I stripped away. Needless to say, I should have been setting $ids[] = $detail in the else statement which I wasn't doing. Anyways, the code worked and things ran even though that bug was there.

I have used three editors/IDEs. I've used:

  • Sublime
  • VScode
  • PHPStorm

PHPStorm was the only one that hinted that that variable may not have been declared. In Sublime I had PHPmd, PHPcs, and PHPlinter installed. Nothing picked up this issue. I've also used php -l and etsy/phan to see if they would hint that this is a problem and they didn't.

I really like using Sublime and I'd like to know if you guys know of any parsers or analysers that would pick this problem up? If not, I suppose I'll need to use PHPStorm but it seems funny to me that there isn't a library out there that picks this up??

Thanks!

0 likes
5 replies
martinbean's avatar

@Kerren I’m struggling to understand what your code example is doing.

If you’re having scope issues, then it usually points to something being too “fiddly” that could do with a re-factor to simplify, rather than look for tools/plugins to “catch” you.

1 like
kfirba's avatar

@Kerren To be honest, I despise conditionals. I will do everything I can in order to get rid of them - Polymorphism, Null Objects, helper methods etc.

If I have to use a conditional, I will do absolutely anything I can to ensure I never use an else statement. I would go for maximum 1 nesting level and won't use an else statement. By doing so, I very very rarely get to the points where a variable may not be declared in my code.

Whenever I find myself using a conditional, I always take a step back, inspect my code and try to figure out how I can get rid of it and what are the issues that this conditional statement may present.

IDEs are much smarter than code editors. They actually scan all your code, build a dependency tree, try to analyze the code and build "branches" which the code execution may take. By doing so, they can give you a detailed analysis of edge cases that you may not have thought about. On the other hand, code editors' understanding of your code is very limited. They don't analyze your whole project. They will analyze the current file or the opened files at best. There might be some packages out there that teach the editor how to inspect and analyze your code a bit better but remember, doing so is not what code editors are for, but what IDEs are there for.

1 like
Kerren's avatar

Thanks for the responses guys!

@martinbean I know there would be many ways to do this, an array_map would probably be a better solution, it was just an example to show the issue :) The point that I'm trying to make is that variable scoping is an issue that will always exist in PHP and I'm trying to find the best way to pick it up! I'm not new to programming but I'm relatively new to PHP. I've always used strict typed and compiled languages so I wouldn't run into these issues before.

@kfirba Your response is really interesting! I come from a C++ background where there was never a move away from conditionals, but I think this is a really cool approach. One of the things I like to do is always return from functions right at the start if the data isn't valid. What you're saying is that I shouldn't stop there, I should avoid else conditionals at all cost. Is this a documented programming paradigm that I could read about? Is it mainly a PHP thing or is it encouraged in all languages?

I suppose, in my case, I could do (again, I'm adding extra steps just to ensure that everyone is on the same page, I wouldn't create $id in this case):

$ids = [];
foreach ($details as $detail) {
        if (is_array($detail)) {
            $id = $detail['id'];
            $ids[] = $id;
        continue;
        }
    $id = $detail;
    $ids[] = $id;
}

Not bad, but often I wonder about readability in this case. We're getting rid of the else statement, but using continue can often leave a bit more uncertainty on what the code below it should be doing. I've often found it easier to say: "If this is true then it does this, otherwise it does this."

Most of the time when there is a continue, I'd explain it as, "at this point we know that it couldn't have been true in the if statement because we wouldn't be able to reach this point if it was." That all sounds great, but from my experience, I've found that a lot of people struggle to comprehend why we know with absolute certainty the first if statement wasn't true compared to when you use an if else.

So that's why this methodology you've described intrigues me, it makes a lot of case for avoiding bugs and problems but don't you think it could have an adverse effect on readability?

kfirba's avatar
kfirba
Best Answer
Level 50

@Kerren Hey.

Well, In your specific case I would probably go with a ternary and a simple push. I know ternaries are exactly the same as if..else.. statements but they ensure that you assign some value to some variable so your variable will always be declared:

$ids = [];
foreach ($details as $detail) {
    $ids[] = is_array($detail) ? $detail['id'] : $detail;
}

As of the continue keyword, I also don't use it that much. It really all depends on the code I'm currently writing. If you have some example code I can show you how I would refactor it and explain my thought process.

I probably won't sacrifice readability for some weird refactor. However, I would be more inclined to give up a little bit of performance to get my code clean. What I mean is, for example, assume you have a loop where you have to use the continue keyword in order to avoid an else statement, I would usually just won't use the continue keyword but add a null to the array. At the end of the loop the array would look something like:

$array = [1, 5, 7, null, null, 4, 3, 3, null]

What I would do now is simply pipe this array to a method like array_filter to get rid of the nulls:

$array = array_filter($array);

So we do sacrifice a bit of performance here since we iterate over the array again but we gain readability and avoid nested code.

1 like
Kerren's avatar

@kfirba That's a really awesome approach! I'm going to look into this further but I really like your argument as to why you do it!

Please or to participate in this conversation.