In my code you can often see me calling global functions using a backslash in front of them: \array_map, \array_filter, \sort and so on. This is not a very common practice and naturally raises eyebrows. Every time I get into a new team or when a new employee joins the team, I get asked the same question for years: “why do you use prefixes for global functions?”

TL;DR
I do this for two reasons: it is self-discipline, and it really speeds up the code a little

Micro-optimization?

Are you serious?! It’s nonsense! This pointless optimization doesn’t save resources in more than a couple of nanoseconds!

Yes, I’ve heard comments like this before, please don’t bother writing another mail like that to me - I know what I’m doing

Let’s start with the so-called “optimization”. In fact, it is absolutely invisible in very small scripts that can be described in a couple of lines of code. Even if we write a couple of hundred or thousand of them, it really won’t affect anything at all - the time and amount of memory consumed will remain at the same level. I don’t want to say that 100% of the time I write exceptional, perfect and cleanest code in the world, so I use even so small optimization. Nonsense! Of course not - I often compromise with myself and write dirty code quickly if only I urgently need to fix something or test some concept. This optimization only works where large computing power is used, where recursions occurs, and where memory needs to be accessed very often

For example, (I can’t tell you all the details, but…) several projects, which I’ve been working on for a long time, contains sections of very old code (10+ years), which constantly interacting with huge amounts of data. Their files contain several hundreds and even thousands of code lines each. There are all kinds of database connections, filtration, recursions and many more scary and difficult things. Does using global namespace helps me to optimise the code? Well, I would lie if I tell you “yes, for sure”. Prefix – is my old habit, so I often type it unconsciously, its impact less than 1% of my recent optimisations:

-Before:  47 processes finished in 5.694s (   ~8.25/s)
+ After: 909 processes finished in  0.72s (~1262.5 /s) (x153)
-Before: 2000 processes finished in 446.369s (7'26") ( ~4.5/s)
+ After: 6000 processes finished in 534.663s (8'54") (~11.2/s) (+248%)
-Before: 34 processes finished in 10min (3.4/min)
+ After: 72 processes finished in 10min (7.2/min) (+211%)

Please note, that all three of these examples are different modules that perform different numbers and volumes of tasks, optimized at different times, in different ways. Then why did I show you them here? Just to brag (:

PHP inside

Okay, jokes aside, let’s finally get to the point. How does PHP understand that this is a global function and not a user one? For example, if we write the following code, then the preprocessor does not care at all whether we put a global prefix or not:

echo abs(-3.14);
number of ops:  5
compiled vars:  none
line      #* E I O op                     fetch  ext  return  operands
--------------------------------------------------------------------------------
    3     0  E >   INIT_FCALL                                 'abs'
          1        SEND_VAL                                   -3.14
          2        DO_ICALL                           $0      
          3        ECHO                                       $0
          4      > RETURN                                     1

Here we can safely say that specifying the scope is redundant and useless. What if we add a scope to our code?

namespace App\Test;

echo abs(-3.14);

Great! Exactly what I wanted to show. In this case, the interpreter trying to find the called function:

number of ops:  5
compiled vars:  none
line      #* E I O op                     fetch  ext  return  operands
--------------------------------------------------------------------------------
    5     0  E >   INIT_NS_FCALL_BY_NAME                      'App\Test\abs'
          1        SEND_VAL_EX                                -3.14
          2        DO_FCALL                        0  $0      
          3        ECHO                                       $0
          4      > RETURN                                     1

So the interpreter performs the following flow:

PHP function search flow

Every time we use a function without specifying what scope it is in, the interpreter uses the INIT_NS_FCALL_BY_NAME operation instead of INIT_FCALL and is forced to perform additional unnecessary operations

And yet, why is this?

Some developers also recommend calling functions from the global scope, others claim it has a big impact on performance. I don’t know if this has any significant effect on modern versions of PHP older than version 7 (it’s very difficult to measure), but I like to think that even with all the ugliness of the legacy code, my fresh code is at least a nanosecond more efficient. I have always admired the pioneers of our profession who launched people into space on computers that operated in kilobytes, rather than gigabytes, as is the case today. And I’m very sorry that we have forgotten how to do this skill today. Now it’s easier for us to buy additional RAM for the server than spending time on optimization

Okay, but this still doesn’t give us anything! We will not get any performance gain if the processor performs a couple of additional operations few times. Business will not wait until you play enough with optimization

Yes this is true. The reason I still do this, despite the fact that PHP has long since acquired JIT and OPcache, is self-discipline. It doesn’t take very long to write another backslash while I’m writing the code. The explanation for this habit is very simple: I always think about the fact that other people will read my code and I always try to write the code as clean as possible, refactoring the previous one if possible. For me, this is as symbolic as the dent in paper that a Canadian engineer’s ring leaves. The old code I’m working with, sometimes throws up surprises like overridden global methods. Thus, I want me and my colleagues to understand the purpose of the function “a priori”, without checking its implementation

namespace App\Test;

function pi() {
    return 2.718281828459045;
}

echo pi(); // 2.718281828459045
echo PHP_EOL;
echo \pi(); // 3.14159265358979
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
function name:  (null)
number of ops:  9
compiled vars:  none
line      #* E I O op                     fetch  ext  return  operands
--------------------------------------------------------------------------------
    9     0  E >   INIT_NS_FCALL_BY_NAME                      'App\Test\pi'
          1        DO_FCALL                        0  $0      
          2        ECHO                                       $0
   10     3        FETCH_CONSTANT                     ~1      'App\Test\PHP_EOL'
          4        ECHO                                       ~1
   11     5        INIT_FCALL                                 'pi'
          6        DO_ICALL                           $2      
          7        ECHO                                       $2
          8      > RETURN                                     1

Function app\test\pi:
Finding entry points
Branch analysis from position: 0
1 jumps found. (Code = 62) Position 1 = -2
function name:  App\Test\pi
number of ops:  2
compiled vars:  none
line      #* E I O op                     fetch  ext  return  operands
--------------------------------------------------------------------------------
    6     0  E > > RETURN                                     2.71828
    7     1*     > RETURN                                     null