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