Why can't PHP have a constant object?
Asked Answered
R

2

19

I have a key-value database table, where I store some settings.

I would like to have these settings in a PHP constant object, since they shouldn't be editable.

In PHP7 we can now do this:

define('MySettings', array(
    'title' => 'My title'
    // etc
));

// And call it with
echo MySettings['title'];

And it works great.

But why can't I do:

define('MySettings', (object) array('title' => 'My title'));

So I could call it like this instead:

echo MySettings->title;
// or
echo MySettings::title;

This is only because I think it's quicker and prettier to type it as an object property/constant ($obj->key, $obj::key), than as array ($array['key'])

Is there any reason this is not possible?

Rimbaud answered 22/9, 2016 at 14:5 Comment(2)
because technically objects CAN'T be constant. they can contain code, which means that the internals of the object can be changed, which means they're not constant. that's why you have constants - it's a promise/guarantee that what you stuff into the constant will NEVER be changed.Tokoloshe
There is a proposal currently under discussion for a future version of PHP to support immutable objects. This would allow a program to create an object with a set of values and those values would be fixed and unchangeable once the object was created. You can read more about it here: wiki.php.net/rfc/immutability. However note that it isn't in PHP now (7.0), and it won't be in the forthcoming 7.1 release either. Depending how the discussions go, it might get into 7.2, but it's too early to promise anything on that at this stage.Videogenic
G
24

For PHP, all objects are mutable. Since constants should never change at runtime but objects can, object-constants are currently not supported.

In the phpdoc about constants, it is stated that:

When using the const keyword, only scalar data (boolean, integer, float and string) can be contained in constants prior to PHP 5.6. From PHP 5.6 onwards, it is possible to define a constant as a scalar expression, and it is also possible to define an array constant. It is possible to define constants as a resource, but it should be avoided, as it can cause unexpected results.

There is an inconsistency with arrays though and no rational is given as to why array constants are allowed. (I would even argue that it was a bad call.) It must be noted that array-constants are immutable, hence trying to change them results in Fatal error as showcased by this code from php7:

<?php
$aNormalMutableArray = ['key' => 'original'];
$aNormalMutableArray['key'] = 'changed';
echo $aNormalMutableArray['key'];

define(
    'IMMUTABLE_ARRAY',
    [
        'key' => 'original',
    ]
);
IMMUTABLE_ARRAY['key'] = 'if I am an array, I change; if I am a constant I throw an error';
echo IMMUTABLE_ARRAY['key'];

throwing:

PHP Fatal error:  Cannot use temporary expression in write context
in ~/wtf.php on line 12

Why it isn't possible to define object constants with a similar error? One has to ask the power that be.

I recommend staying away from arrays and objects as constants. Rather create an immutable objects or use immutable collections instead.

Since you are looking for a certain syntax, there already is the concept of class constants.

<?php
class MyClass
{
    const CONSTANT = 'constant value';

    function showConstant() {
        echo  self::CONSTANT . "\n";
    }
}

echo MyClass::CONSTANT . "\n";

$classname = "MyClass";
echo $classname::CONSTANT . "\n"; // As of PHP 5.3.0

$class = new MyClass();
$class->showConstant();

echo $class::CONSTANT."\n"; // As of PHP 5.3.0

It's also possible to define them in interfaces.

Guadalupeguadeloupe answered 22/9, 2016 at 14:17 Comment(5)
Thanks for your answer. In Class constants I would have to "hardcode" all constants in the php file, but I would like to make it dynamic, so when I make a new row in the database setting table, it is available as a setting. But this is not possible with class constants. If it makes sense. This is why I use constant array.Rimbaud
@user245734 Though appreciated, comments aren't meant for thank-yous. It's enough to upvote or to accept an answer :)Guadalupeguadeloupe
@user245734 And according to your follow-up question regarding to avoid to hardcode all the constants: That's a follow-up question and not entirely in the scope of your original question. Feel free to open a new question.Guadalupeguadeloupe
-1 "Constant objects make no sense as objects are mutable by definition." Constant objects can make perfect sense, esp. with value objects. Secondly, "mutable by definition" doesn't really explain anything. Arrays are "mutable by definition" yet you go on to show that constant arrays are magically immutable.Dukie
@leo-the-manic I may have misworded. I am not saying that immutable objects, as a design choice, are a bad idea. I am saying that in the context of php as a language, it views all objects as mutable. And yes, PHP does magically create an immutable array for an array constant. Yet it doesn't for objects. I was showcasing an inconsistency on PHP's part. They may fix this in the future either by featuring ImmutableObject or by removing the array constant. Or maybe this will be yet another entry on php ;) Does this clarify my intent?Guadalupeguadeloupe
M
0

I use a constant to make a monolog logger available globally in all my projects. It leads to very compact code.

<?php declare(strict_types=1);
include './vendor/autoload.php';
$log = new Monolog\Logger( SETTINGS['log']['name'] );

$log->pushHandler(
    new Monolog\Handler\StreamHandler(
        SETTINGS['log']['location'] . '/'. SETTINGS['log']['name'] . '_error.log',
        Monolog\Logger::ERROR
    )
);
$log->pushProcessor( function ($record) {
    $record['extra']['user']      = $_SESSION['username'] ?? '';
    $record['extra']['ip']        = $_SERVER['REMOTE_ADDR'] ?? '';
    $record['extra']['sessionId'] = substr( session_id(), 0, 8 );
    return $record;
} );
/**
 * @global Monolog\Logger LOG - the logger
 */
define( 'LOG', $log );
unset($log);

In my scenario SETTINGS is a global array

<?php
define( 'SETTINGS', parse_ini_file( './config/settings.ini', true );

Now logging becomes something simple and compact as

LOG->info('Information!');
Monochromatism answered 8/6, 2024 at 14:8 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.