Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:107998 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 23636 invoked from network); 5 Jan 2020 23:48:45 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 5 Jan 2020 23:48:45 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id AC386180511 for ; Sun, 5 Jan 2020 13:53:28 -0800 (PST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL, SPF_HELO_NONE,SPF_NONE autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS15169 209.85.128.0/17 X-Spam-Virus: No X-Envelope-From: Received: from mail-yw1-f44.google.com (mail-yw1-f44.google.com [209.85.161.44]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange ECDHE (P-256) server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Sun, 5 Jan 2020 13:53:27 -0800 (PST) Received: by mail-yw1-f44.google.com with SMTP id u139so21124930ywf.13 for ; Sun, 05 Jan 2020 13:53:27 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=newclarity-net.20150623.gappssmtp.com; s=20150623; h=mime-version:subject:from:in-reply-to:date:cc :content-transfer-encoding:message-id:references:to; bh=LrDx2BTX9TOMqNnSwAnX+MacJRUg6j4D8VBU+IsP5og=; b=MhFMwwEV3WmI/RlUbe6mnvxNqo4vBYcgG/wkqKNVYRJNWuTQa4P/HKL80b5CEzGw/+ 0laZDdWMcE5aUp0l+8UJM6V2/uYb3w/gAxCaKVipsBME/YwxJH95GBnNoC3egp/7Oi+m iKomRzQ7cMhYChd5/HD6hP0Q2hjIatxr+AlC5ZSu9E9aAkgaVxFnn1/x37cjlVd52DaJ IU6xVmpeNbbKZPZ15CdoZmIueehcpkEKL6eAq/cU3itSt3rD59BsmqGeFKvkyBvu3NWV fMsXPBVcyeCyzuRpU3RnOKlmVBYIlTQtCLIXpJoQxk5PAgUA3YiZtVWB0g97/27lnUTF u7gg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:mime-version:subject:from:in-reply-to:date:cc :content-transfer-encoding:message-id:references:to; bh=LrDx2BTX9TOMqNnSwAnX+MacJRUg6j4D8VBU+IsP5og=; b=D6rLjBPyMlQxKQbcN+7iM36BUbD2mBAuk310IKHvZr3Ar6uS7c4ijRqWS1pp0f2gau w59HbZgesKxSSSAoKKXEg1IKNJprIb180n2QL9Wo1QhALZUZWDU017g4gnGh8IrAAein SFQfHIiF9N1YnE6/SLJVroOf0dmX/MIHhkMQCNjwh4wxUl8fXsK/dr4HrvQ5XldoC8Dt 9JODgn+/F2Jq3a5ruOyn7/ak27Oty4jdFliGkhXG2rJyEtJcFdnUXadSWOVJY/nVXiQ+ hEf5EZoTCMoraA96CeudVc3Vebw0mVeIk1Cy/Z62cHx3RXBMmoKdsYE8mx0NRofd0MMy 3oig== X-Gm-Message-State: APjAAAXchNQ3jhcHKao42f9zNDWPN9WcW8gQaEBBXOtKSzNu1Dd08nfR vpP38qtGKq5d8OQl62EUPVA3GQ== X-Google-Smtp-Source: APXvYqwbg4Q8HS0x0iGu8sgC3G7Robmv1fyhzPPktSeoco1js0hObq/BGKhKlcgGKE2K4NGiGqZFbw== X-Received: by 2002:a81:5206:: with SMTP id g6mr77449407ywb.216.1578261206461; Sun, 05 Jan 2020 13:53:26 -0800 (PST) Received: from ?IPv6:2601:c0:c680:5cc0:64a1:dd94:3e49:c5e1? ([2601:c0:c680:5cc0:64a1:dd94:3e49:c5e1]) by smtp.gmail.com with ESMTPSA id b192sm27077646ywe.2.2020.01.05.13.53.24 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sun, 05 Jan 2020 13:53:25 -0800 (PST) Content-Type: text/plain; charset=utf-8 Mime-Version: 1.0 (Mac OS X Mail 12.4 \(3445.104.11\)) In-Reply-To: Date: Sun, 5 Jan 2020 16:53:24 -0500 Cc: internals@lists.php.net Content-Transfer-Encoding: quoted-printable Message-ID: References: <5e0d723f.1c69fb81.e2ae8.24e2SMTPIN_ADDED_MISSING@mx.google.com> <74F2DBFC-E63C-428C-A37F-2D0CEE15AD0F@newclarity.net> <53556dfb-44ce-f902-204c-9a7da9484a61@gmail.com> <65567C7C-CF0F-4562-8943-F1F302134B07@newclarity.net> To: Rowan Tommins X-Mailer: Apple Mail (2.3445.104.11) Subject: Re: [PHP-DEV] Initializing constants once, with code? From: mike@newclarity.net (Mike Schinkel) > On Jan 5, 2020, at 3:17 PM, Rowan Tommins = wrote: >=20 > 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. Yet you called my list of URLs enums, and they are not at all arbitrary = and absolutely want to change. We can both agree that enums for 0, 1, 2 etc. are not in use-case I am = discussing. Maybe you misspoke when you called my list of URLs enums? Or I misread? > 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. I take it you have never used Pantheon hosting then? You create a named = environment to match a Git branch.=20 "dev" is not "local" in this content. "dev" is the place developers = push code to test remotely. Then they push to "test" for QA to = evaluate. At least for this client. That said, my client wants to move to many "dev" and "test" = environments, one for each JIRA epic, so we would like to be able to = initialize the API urls based on the current subdomain.=20 > 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. What is "better" in this context is one's opinion. You might not find = it beneficial, but I would.=20 > 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 use and have used PhpStorm extensively, since prior to 1.0. But = PhpStorm does not make it easier to do code reviews on Github, or even = read code in PhpStorm. Yes, I can navigate them, but to still adds = cognitive load.=20 Honestly, we are debating preferences here. Can we focus on objective = things? > "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. It was a design decision in that maybe it did not occur to them that it = would be useful; IOW a design by omission. Design decisions can be changed. PHP 5 changed the design decisions of = PHP objects and added the __set() method. Before then it could have = easily been argued that variable accessed a memory location, but never = called code. But then that design decision was changed. =20 So there is no reason I've heard thus far that this one could not be = changed too. > 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. > "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. Excellent point. =20 Ruby has the .replace method for constants and can thus assign at = runtime: =3D=3D=3D=3D=3D=3D=3D=3D=3D https://stackoverflow.com/a/6712438/102699 Javascript can assign constants at runtime: =3D=3D=3D=3D=3D=3D=3D=3D=3D fn =3D function() { return "World"; }; const who =3D fn(); alert( "Hello " + who ); C++ has const member functions (not exactly the same, but similar): =3D=3D=3D=3D=3D=3D=3D=3D=3D = https://www.linuxtopia.org/online_books/programming_books/thinking_in_c++/= Chapter08_014.html Python adds a final qualifier to turn variables into constants. Thus is = supports initializing constants: =3D=3D=3D=3D=3D=3D=3D=3D=3D https://stackoverflow.com/a/47821212/102699 http://code.activestate.com/recipes/65207-constants-in-python/ Java creates class constants with `public static final` which can be = initialized with code: =3D=3D=3D=3D=3D=3D=3D=3D=3D = https://www.javaworld.com/article/2076481/use-constant-types-for-safer-and= -cleaner-code.html I think that is a fairly conclusive list of highly-used languages, all = of which allow constants to be initialized with code. This list would = imply any assertion that constants must be handled at compile time is = not applicable for many other languages so I would argue to not a = universal principle. Also it would imply that allowing constants to be initialized via = runtime code would not disrupt the time-space continuum, either. > 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. Again, I ask if that your unease has more to do with status quo bias vs. = something fundamentally wrong with the concept? > It's a limitation in the very basic sense that it limits what you can = do. You can't write this, for instance: >=20 > class API { > private $config; > public function __construct($config) { > $this->config =3D $config; > } >=20 > const URL { > return $this->config->getValue('API_URL'); > } > } But you could do this: class Api { const URL:string { return Config::get()->api_url; } } class Config { public $api_url; private static $_current; function __construct($args =3D array()){ $this->api_url =3D $args['api_url']; } static function get():Config{ if ( ! isset( self::$_current ) ) { trigger_error('must call Config::set() before calling = Config::get()'); die(); } return self::$_current; } static function set( Config $config ){ self::$_current =3D $config; } } Config::set( new Config(['api_url' =3D> 'https://api.example.com']) ); //... $api_url =3D Api::URL; Any way, why again must perfect be the enemy of the good? > 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. Ah.=20 > 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. Well, I am suggested one-time only because I assumed that one-time only = _is_ the only thing that is fundamental to `const.` But I can see uses = for being able to redefine them =E2=80=94 when running unit tests =E2=80=94= but I was not planning to ask for that. > Many people would say the kind of global state you're talking about is = an anti-pattern. Well, Larry did, which is reality is an appeal-to-authority argument and = not an argument on the merits. =20 But I used "anti-pattern" because I did not think I was trying to = convince anyone against adding a pre-processor, so it was just easier to = write! > I'm just looking for solutions to your use case, which as I understand = it is values which change rarely based on configuration. I honestly do appreciate it. You are generally very good about that = kind of thing. -Mike=