92

I am getting an error:

Fatal error: Constant expression contains invalid operations in config.php on line 214

That line was:

 protected static $dbname = 'mydb_'.$appdata['id'];

Whether I did any mistakes in quotes? Or somewhere else?

My search for the error message only showed a different source cause (a dynamic default value in a function definition).

Álvaro González
  • 142,137
  • 41
  • 261
  • 360
Raja Gopal
  • 1,845
  • 1
  • 17
  • 34
  • If you don't say what's unclear about the explanations you've found people will possibly waste time composing the same information again. – Álvaro González Oct 21 '16 at 08:42
  • @ÁlvaroGonzález Sorry mate , The answer by Al Fonce here cleared my issue . actually other similar titles i found here in SO has only similar title but the query differs mate . That is why i asked this question – Raja Gopal Oct 21 '16 at 08:47
  • 1
    Then another way to express that is just "I couldn't find a similar question here" and I'd say that's explicitly assumed if you don't say anything. I've taken the liberty of editing your question to reflect that. Never mind, the question itself can be pretty interesting if there aren't dupes (and if there're dupes it'll hopefully be linked to one). – Álvaro González Oct 21 '16 at 11:21

6 Answers6

84

From the official Php documentation :

Like any other PHP static variable, static properties may only be initialized using a literal or constant before PHP 5.6; expressions are not allowed. In PHP 5.6 and later, the same rules apply as const expressions: some limited expressions are possible, provided they can be evaluated at compile time.

So you cannot initialize a static variable with another variable. Replace $appdata['id'] with a constant string or remove the static attribute.

This is because all static declarations are resolved in compile-time, when the content of other variables is not known (see this other page of official doc).

Aslamkv
  • 529
  • 1
  • 5
  • 7
Al Foиce ѫ
  • 4,195
  • 12
  • 39
  • 49
  • 2
    Can you elaborate on **compile-time**? What would that even mean for an interpreted language like PHP? Even in compiled languages like C#, we wont have such limitation using static constructors. – Ahmad Mar 04 '21 at 18:18
  • I think the issue is values of static variables need to be initialized as soon as the class is read. Other variables may not be initialized when the class file is read. Referring to a possibly uninitialized variable to initialize a static variable is not logically allowed. This causes an error. – nuiun Jan 27 '22 at 11:59
34

Unless you mess with reflection, the only way I can think of to have a static private/protected class property with a dynamically generated value is to calculate it outside the class:

class Foo
{
    protected static string $dbname = DBNAME;

    public static function debug(): string
    {
        return Foo::$dbname;
    }
}

$appdata = [
    'id' => 31416,
];
define('DBNAME', 'mydb_' . $appdata['id']);
var_dump(Foo::debug());

In your precise use case, however, it's possible that there's simply no good reason for the property to be static. In that case, it's as straightforward as using the constructor:

class Foo
{
    protected string $dbname;

    public function __construct(array $appdata)
    {
        $this->dbname = 'mydb_' . $appdata['id'];
    }

    public function debug(): string
    {
        return $this->dbname;
    }
}

$appdata = [
    'id' => 31416,
];
$foo = new Foo($appdata);
var_dump($foo->debug());
Álvaro González
  • 142,137
  • 41
  • 261
  • 360
  • I believe this works only because you are effectively using constants. Try using an environment variable that cannot be resolved at "compile" time. – Pierre-Luc Bertrand May 08 '20 at 21:20
  • 2
    @Pierre-LucBertrand I'm [unsure](https://3v4l.org/6NLqC) of what you're trying to say. – Álvaro González May 09 '20 at 08:25
  • Instead of having $appdata= ['id'=>...], try using an environment variable instead of the constant 31416 and you should reproduce the same problem as the question. The difference would be that the environment variable is not resolvable at compile time unlike 31416. – Pierre-Luc Bertrand Jul 24 '22 at 22:06
  • @Pierre-LucBertrand I still cannot reproduce: https://3v4l.org/6VNEX#v8.1.8 - Could you please share an online fiddle that exhibits such behaviour? – Álvaro González Jul 25 '22 at 06:14
15

This is because a static variable contains a constant value in it. But in your case:

protected static $dbname = 'mydb_'.$appdata['id'];

$appdata['id'] is dynamic that can change its value during the execution. That's why the error is showing.

Mayank Pandeyz
  • 25,704
  • 4
  • 40
  • 59
7

I had this error and my fix was to not declare a date within a class property array

public static $config_array = array(
    'start_date' => date('Y-m-d H:i:s') // No can do
);
Jack
  • 3,271
  • 11
  • 48
  • 57
0

In my case the solution to this issue was to create a singleton class so the variable's value is initialized (calculated) only once and still have access to it whenever I need.

(Extra info: The singleton is a design pattern which stricts you to have only 0 or 1 instance of your class in your entire program. There are several design pattern, I collected 115 of them so far on a single image)

In your case the code would look like this:


class DataBaseConfig {
                 
    private static $instance;
    private $dbname ;
                
    private final function __construct() {
        $this->dbname = 'mydb_'.$appdata['id'];
    }
    
    public static function getName() {
        if (!isset(self::$instance)) {
            self::$instance = new DataBaseConfig();
        }
        return self::$instance->dbname;
    }
}

You can use it like DataBaseConfig::getName() for the shortest / simplest version.

In reality you have more complex classes and functions so by defining a getInstance() function you will avoid repeating the <check instance> - <create instance process> lines for every function you add.

(Extra info: 2 synonym paradigms DRY - Don't Repeat Yourself and DIE - Duplication Is Evil)

This is the refactoring you need:

public static function getInstance() {
    if (!isset(self::$instance)) {
        self::$instance = new PhpStarter();
    }
    return self::$instance;
}

public function getName() {
    return $this->dbname;
}

Use it like $db = DataBaseConfig::getInstance(); then $db->getName() and $db->getSomethingElse() for the other functions.

Dani Feldman
  • 156
  • 2
  • 11
-1

For your information:- I got the same error by using some characters in a constant expressions.

public static $dbPassword="mAkE-34@-||sR";

This is what caused the error and I removed this || which is the logical OR operator characters from the string and it worked.

Sameera
  • 41
  • 8