0

PHP - Testing a simple function with a static array variable. I assume the static variable declared in the function would make it available outside of the function.

This function just takes a message and adds it to the errors[] array, and then be able to use this list of errors[] outside the function.

I get the error message: "Notice: Undefined variable: errors in....on line 10"

Line 10 has the code, "print_r($errors);"

function addErrors($errmessage){
    static $errors = array();
    $errors[] = $errmessage; 
}
addErrors('test1');
addErrors('test2');
print_r($errors);

Your input is appreciated!

1

5 Answers 5

4

$errors is a static variable inside the function, you cannot access it from the global scope.

here's an example how to achieve what you are trying to do :

PHP 7 < :

<?php

/**
* @param string|null the error message to add or null
* @return array|null returns all errors if provided with null 
*/
function errors($error = null) {
   static $errors = [];
   if($error !== null) {
       $errors[] = $error;
       return null;
   } else {
       return $errors;
   }
}

errors('Error !');
errors('Another !');
print_r(errors());

PHP 7 >= :

<?php

function errors(string $error = null): ?array {
   static $errors = [];
   if($error !== null) {
       $errors[] = $error;
       return null;
   } else {
       return $errors;
   }
}

errors('Error !');
errors('Another !');
print_r(errors());
Sign up to request clarification or add additional context in comments.

7 Comments

Thanks! However, your example code produces an syntax error: "unexpected ':', expecting '{' in...". But when I modify it a bit, it works fine: function errors($error = null){ static $errors = []; if($error !== null) { $errors[] = $error; return null; } else { return $errors; } }
what php version are you using ? my code is valid php 7.0 code, however i'm gonna add another one for php 5.*
I'm using php 5.5.15... maybe that's why it gives a syntax error? Can you tell me the purpose of the "?array" code?
i highly recommand you upgrade to php 7.2, it is way much faster and consumes way much less cpu and ram , see : secure.php.net/manual/en/migration70.php , secure.php.net/manual/en/migration71.php and secure.php.net/manual/en/migration72.php
Well done, reacting fast. I could tell what happened there and that it does not tally with your normal level of language. ;-)
|
4

You define the $errors variable inside a function scope, outside the scope it won't exist.

Static only means that it will be created once in this case, not that it's available outside of the scope, a global keyword would possibly help you, but honestly, I'd recommend another approach (global is a bad practice).

You could return the errors array from the method:

function addErrors($err) {
  static $errors = [];
  $errors[] = $err;
  return $errors;
}

A better way would probably be to create a class though:

class ErrorHandler {
  private static $errors = [];

  public static function addError($error) {
    self::$errors[] = $error;
  } 

  public static function getErrors() {
    return self::$errors;
  }

}

Then use it as:

 ErrorHandler::addError('error');
 print_r(ErrorHandler::getErrors());

Comments

3

This is a gap that PHP (and other programming languages) don't tell in their books directly upfront: You can have two times the same variable name (in your case $error), but even the same, the two do not identify the same variable (address the same memory).

This might seem little straight forward at first, but it becomes more sense when it is about structuring a larger program as considerable all well understandable variable names are limited, so making every variable by it's name accessible in the global name-space would pretty fast mess up the whole program code.

So I see multiple routes here on how to deal with this if you're interested (if not, here is some existing Q&A regarding the static keyword in a PHP function).

The first one is quite lazy and most likely unsafe in terms of data processing, so the overall programming code needs to be very precise to make safe use of it: "don't re-implement the array, just use it globally". You can do that with a global variable.

Initialization should be done in the beginning of the application:

$GLOBALS['errors'] = [];

You can then add to that variable new entries whenever you feel it is needed:

$GLOBALS['errors'][] = $error;

And if you need to obtain the errors as a list again, just read it out:

var_dump($GLOBALS['errors']);

This actually is the global variable name errors. Global variables are powerful but also expensive in their maintenance as any code could - by intended or by error - reset all errors for example or even more harsh, turn the array into a string and next time some code wants to add a new entry will fail.

So how could a solution not using a global variable look like? By the cost (and with the benefit) of more controlled access to your errors collection, you can create an object representing that list of errors and pass it around where-ever you want to add an error.

But before showing the object instance, I first show an example of a static class as it might be more close to your mental model w/ the function and it's static variable-

Implemented with static modifiers, you can create an inaccessible global variable (private static global) which is only accessible by the function that adds messages to it (and other static function of the same class).

It is then easy to add another globally accessible function that is able to return that variable's content:

final class Errors
{
    private static $errors = [];

    public static function add(string $error): void
    {
        self::$errors[] = $error;
    }

    public static function get(): array
    {
        return self::$errors;
    }
}

This class provides limited access to the otherwise not accessible static variable Errors::$errors.

It does automatically initialize the moment this class definition is loaded (e.g. via include/require or an auto-loader), new errors can be added via:

Errors::add($error);

And errors can be read out via:

var_dump(Errors::get());

This is now more safe to use as the global variable, however still there is only one global list of errors and every part of the code can access it via the Errors::... class identifier (the name of the class).

So the problem that after some time all usable names are consumed is not solved by that.

To prevent that the class could be turned from static into non-static so moving from global static functions to object instances. This is easy to do, basically just removing the static modifiers and switching from self::$ to $this->. That easy I do the whole example at once:

final class Errors
{
    private $errors = [];

    public function add(string $error): void
    {
        $this->errors[] = $error;
    }

    public function get(): array
    {
        return $this->errors;
    }
}

Now to get this class to work, it needs some more work with the benefit of better control. First of all it needs initialization:

$errors = new Errors;

Afterwards that errors collection needs to be passed to every place where an error needs to be added:

$errors->add($error);

And if you like, read out all errors collected so far:

var_dump($errors->get());

This last variant needs you to manage (and therefore think about) which parts of your code need to have access to which specific errors collection (as you could create more than one). So this is more work on first glance, however simplifies things a lot in the long run. You can change the errors collection (store in a file as well next to the array for example) w/o needing to change all the places where a message was added.

You can provide a different error collection object for different uses, e.g. in a testing scenario or of a sub-module of your program only.

So this gives also a lot more flexibility (just start minimal).

The static class in the middle might seem as the holy grail now, but I'd say these are only mediocre and will put a lot of drain to your code quite fast as they are not as powerful as global variables but also consume the name which can not be easily changed as your application grows bigger.

If the use is clear, global variables can be a powerful tool, also static access. But the devil is in the details and on a more differentiated level, it's often quite useful to go with object instances in the meaning of object oriented programming.

  • global variable - memory object

  • object variable - programming object (gives you more control via the class definition to control changes over time, code and data form their own unit)

Comments

1

From the documentation:

A static variable exists only in a local function scope, but it does not lose its value when program execution leaves this scope.

To make the variable available outside the function scope you could instead use the global keyword:

function addErrors($errmessage){
   global $errors;
   $errors[] = $errmessage; 
}

Reference

Comments

0

There may be good reason not to make it global. The variable $errors is not available outside the function. You can see the static variable actually working like this:

function addErrors($errmessage){
   static $errors = array();
   $errors[] = $errmessage; 
   print_r($errors);
}
addErrors('test1');
addErrors('test2');

1 Comment

Your answer could be more clear about how to retrieve the error information stored previously.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.