On 05/01/2020 19:08, Mike Schinkel wrote:
How are enums a terrible example? They are exactly my use-case. PHP does not have declared enums, so class constants suffice.


They seem a poor example of something that you would later want to "evolve" using the proposed new feature. An enum is, by definition, a set of values that covers all possibilities, often with completely arbitrary values.


BTW, what are "true constants" in this context?


Sorry, I meant what I called below "type 1": a value that is completely hard-coded and will never change.


For one of my client's these get changes based upon the APIs environments that have the updated data.


I'm struggling to imagine how this would work. I've seen plenty of code that needs to know "the current environment", but "the name of the current development environment" seems an odd thing to have a constant for.


The benefits of being scannable are not limited to enum use-cases. The above is more scannable than the following, especially if I had 10+ values:


Well, it would be more "scannable" if every method in the class was written on one line - and indeed you can do so if you want - but that's not inherently better.

If a class has a bunch of different functions and constants in, I'll generally use an IDE or editor plugin to navigate them, and rely on them being well-named, rather than minimising the whitespace between them.


I disagree, I think constants being a literal value is a design decision, not an implementation one.

How is this not just status-quo bias?


"Constants are defined at compile-time" is a status quo in the same sense as "variables can be assigned to" is a status quo - you could certainly design a language differently, but it's not just something that happened by accident, it's a design decision.



As I just replied to Larry, there are continuous changes in PHP that require developers to learn new features. How is this just not a new feature to learn?


An interesting exercise is to ask if there are other languages that take a different decision - it's not decisive, either way, but it can be suggestive.

For instance, "are names case sensitive?" and "can functions accept the wrong types without an error?" are both things that vary widely between languages. "Can constants be evolved into something that is initialised on-demand?" is not something I'm aware of examples of elsewhere. That could be because nobody's thought of it before, or just that I haven't come across it, but it could be because there's a better solution to the underlying requirement.



What if instead of the above we allow this?

    immutable USER_ID {
        return $_GET['user_id'];
    }


Then const would be for type #1 and immutable would be for type #2 and #3. But they would both be accessed by ClassName::USER_ID. This would meet my objective for evolvability of code.


I think the syntax being the same when you *reference* the value bothers me more than how it is declared. If I see ClassName::USER_ID, I expect the value to be the same each time the code runs, and to be able to find the value directly in the source.


As Larry mentions, the proposal is also limited by "globalness". Since constants are always static, the initialisation code can only access global and static state, so you can't inject a configuration object into your constructor then use it to initialise constants.

I don't see why this is a limitation


It's a limitation in the very basic sense that it limits what you can do. You can't write this, for instance:

class API {
    private $config;
    public function __construct($config) {
        $this->config = $config;
    }

    const URL {
         return $this->config->getValue('API_URL');
    }
}


And since they're write-once, you can't use them for Laravel-style "facades", where the access is static, but can be swapped out at run-time.

Since I am not up to speed on Laravel, I am not sure what you mean here by "swapped out at runtime."  Laravel can have different facades are different times during the page load?  Wow, that seems worse that having an initialized constant immutable for the entire page.


Laravel's "facades" are global variables hidden behind static methods. So you write "DB::query($sql)" as a short-hand for "DB::$currentInstance->query($sql)". Most of the time, you just treat it as static, but if you want to write tests, for instance, you can inject a mock as the current instance.

An interesting thing is that you can evolve a class that really is static and replace it with one of these facades. Unfortunately, the same wouldn't be true with initialise-once constants, because once the constant had been read, you couldn't swap it out in another test.


Perhaps a better angle to look at is something like the C Pre-Processor - manipulating the code at compile-time so that multiple different versions of the code can be created from the same source, but constants are still constant at run-time. I know there are tools out there already to do this, but have never used one.

Oh God no!  Pre-processors are definitely an anti-pattern, in my book.  I came to that conclusion sometime in the 80's and have yet to see anything that changed my mind.


Many people would say the kind of global state you're talking about is an anti-pattern. I'm just looking for solutions to your use case, which as I understand it is values which change rarely based on configuration.

Regards,

--
Rowan Tommins (né Collins)
[IMSoP]

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to