I have some arrays storing the possible parameters for some 3D printer commands. I use this to check if the command is legal. I am confused about where I should put these arrays. These arrays will only be accessed in the formatcheck function, and the function will be called many times as there are thousands of commands to check. Should I put these in the formatcheck function as variables or at the beginning of the class the formatcheck function is in, as private static variables?
public function checkFileGcodeFormat()
{
$Ms = array(82, 83, 84, 104, 106, 107, 109, 140, 190);
$Gs = array(0, 1, 20, 21, 28, 90, 91, 92);
$Ts = array(0, 1);
if (! ($this->hasM() && $this->hasNoXYZ() && in_array($this->M, $Ms)) || ($this->hasG() && in_array($this->G, $Gs)) || ($this->hasT() && $this->hasNoXYZ() && in_array($this->T, $Ts)) )
return false;
else
return true;
}
or:
private static $Ms = array(82, 83, 84, 104, 106, 107, 109, 140, 190);
private static $Gs = array(0, 1, 20, 21, 28, 90, 91, 92);
private static $Ts = array(0, 1);
...
...
public function checkFileGcodeFormat()
{
if (! ($this->hasM() && $this->hasNoXYZ() && in_array($this->M, self::$Ms)) || ($this->hasG() && in_array($this->G, self::$Gs)) || ($this->hasT() && $this->hasNoXYZ() && in_array($this->T, self::$Ts)) )
return false;
else
return true;
}
I think that the defining array a property is making more sense, as arrays defined inside the methods are created on every call.
But I want to make another point. If you have rather large arrays to look up value in, it is more important how you structure them. I would suggest this:
Having this structure you can use
isset
(O(1)
) instead ofin_array
(O(n)
).Here are some other questions regarding
isset
vs.in_array
:what is faster: in_array or isset? [closed]
in_array vs isset - perfomance
And here are some posts with benchmarks:
The last one is rather old, but I think the ratio holds.
So to sum up. When you use
isset
the searching time is constant (it actually might vary, but this can be ignored). When you usein_array
the searching time depends on element position (and so on array size). Even on small arraysisset
works faster.TL;DR: Use a class constant for maximum performance (see at the end of the answer).
Let's look at the performance characteristics of the different versions (and why):
PHP 5
Arrays in static properties are created at compile time, very quickly, without involvement of the VM. Accessing static properties though is a bit slower than accessing normal variables, but still much faster than recreating the array on every run.
Arrays in normal functions get re-created at run-time with every run, in any case. And creation at run-time in VM means that every element is added one-by-one, in individual opcodes, which means quite a bit of overhead (especially if the array is larger than just 1-2 elements).
PHP 7.0
Arrays in normal functions [in general] are created a bit faster due to array creation in general being sped up (optimizations in HashTable handling). If it's all constant values, it's cached in the internal constant values array, but duplicated upon each access. However doing a direct highly specialized copying action is obviously faster than adding elements one-by-one to the array like in PHP 5.
Opcache is marking them as IMMUTABLE internally, which allows direct access [so you get full speed with opcache]. (See also https://blog.blackfire.io/php-7-performance-improvements-immutable-arrays.html)
PHP 7.1
Arrays are natively always cached in the internal constant values array, with copy-on-write semantics.
Now using a static property is slower as looking up a static property is less performant than a simple write to a variable. [Direct access to a variable has no extra overhead.]
Also note that since PHP 5.6 you can declare (class) constants with the value of an array. PHP 7.1 allows direct substitution of class constants of the same class and will add the array directly to the internal constant values array for direct usage with in_array.
I.e. the fastest code is (with 7.1 at least):
If they NEVER change then you should be formatting as
const
. There are baked in at compile time and therefore will be the fastest.or
Some notes:
define
but baked in at compile time, so slightly faster than defines and variable arrays.The one sentence takeaway: Class constants may be quicker, but memory probably won't matter, and using the Dependency Injection Design Pattern will be more memory efficient and flexible.
While a class constant or static property will be faster than creating an array in a function (see bwoebi's answer) because it's built in memory once and can be accessed multiple times, it is in no way the most efficient method available, or the recommended way to solve the root problem the OP is aiming to solve.
If you are certain that no data is ever going to change in the future, or you're never going to want to use different sets of data at different times, even for testing, then you may be able to get away with this method anyway. If you want more flexible code, class constants or static properties can cause some serious problems. As I'll explain later, the amount of memory used or saved is unlikely to matter. More important considerations are:
Before committing to the most memory efficient route, be sure to balance other forms of efficiency, such as efficiency of your time in developing and debugging.
Why Memory may not matter
Due to the speed of modern computers, the performance hit you experience between the two versions should rarely make a difference. Disk I/O is more often an issue than memory. If your server is operating on a VERY small amount of memory and you expect very high volume, then the memory efficiency of your code will be more important than if you have moderate volume and moderate memory.
To put things in perspective, see this article on efficiency of arrays in PHP. The takeaway? Even though PHP5 arrays are horribly inefficient, even an array of 100,000 integers will take up about 14M. That's a LOT, but considering that the average PHP script has a memory limit of 128M, and the minimum server recommendations call for about 2 GB of memory, this suddenly looks different.
That means that you should worry about this if the rest of your code is inefficient, or you have high volume compared to low memory. That will cause your application to slow down and/or your system to crash.
Regardless, in a situation where you're exploring architectural choices from the beginning, I would strongly recommend a design pattern. Namely, the Dependency Injection design pattern. This is for a number of reasons, including code flexibility and unit testing, but also has a friendly memory footprint. Because of this, it would probably be considered best practices over either of the two options you are recommending.
Why not static properties
At the outset the easiest route is to use static properties. However, in my experience, the easiest route is not always the best route, and can frequently be the hardest to maintain. One problem here is that your functions/methods will probably be calling another class within. As an example, let's create two classes:
MyFooClass
andDoStuff
, and see how they might interact by default.Now, if you ever want to insert different array values for different purposes, or you want to unit test with fewer or more settings, complications abound.
Dependency Injection to the Rescue!
Like all design patterns, Dependency Injection solves a problem. In this case, the problem is easily and efficiently passing values between multiple functions/methods without sacrificing flexibility. Using a basic DI pattern, you can get your arrays initialized in non-static properties and pass a single object containing this array property to every part of your code. That would allow you to eliminate your concern about performance.
Example:
In your
MyBarClass
, you are assigning aMyFooClass
object to a property$foo
. You can then call any public method or property from this object with$this->foo
. For example:$this->foo->checkFileGcodeFormat()
.With this design pattern:
Conclusion
If you are really looking into understanding how code performance can be measured, you should get familiar with Big-O notation.
What is Big-O? Big-O cheat sheet
Other than that, define them as protected class base properties for static data.