Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:107986 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 17951 invoked from network); 4 Jan 2020 23:21:08 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 4 Jan 2020 23:21:08 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 89B721804F6 for ; Sat, 4 Jan 2020 13:25:38 -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 ; Sat, 4 Jan 2020 13:25:38 -0800 (PST) Received: by mail-yw1-f44.google.com with SMTP id t141so20200115ywc.11 for ; Sat, 04 Jan 2020 13:25:38 -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=QKUxku8a1RlLF9g/JRlVS45leN6b47Bt+fpAFxyTsH8=; b=12qrEvbZJK2aNrh1wEGvAvGNORtVL4nOJ4LMUbZurhMGWenfB8qPbLBgG3cJV5MdnC PAYsXYkFv6lnHB3Xn4AMFEKarElFCJeh0LVDmFvQCAzfeCcc413wRBbNQGFQ2ygEPnY1 RQqhMWET85UjNwQLCEBGAXNkztfg5y3ZCvikJWzoRSOO2relfI42x/ycF2rMNGLAybHR zyKPIEK6jJUk8R3P6d5OXURcZ4nr+jovPv8U4cPkZaUxYLZ/tp7+ooa0mzZCJhJMk3Hu RiWDsvbiSiL0F3RD8E7bOY42eUK/N54Q2a9FXdLawVigErfEqG+6cIO+Q2KvDL/UGIi4 l/2Q== 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=QKUxku8a1RlLF9g/JRlVS45leN6b47Bt+fpAFxyTsH8=; b=D1pEYaRyzQYD8t5EcSrOtSzm5N2V6cCIVFXu4Bufj6mbo4L3eSQQBuIIXxkYlLUy95 uIv+6juFLdRc/xMng43x2blU1qIK2wjCMftNY1arMVKKTEnbzmjHjz1qAnQj1Ristsas 4wKLzyt58l9WAV1d4gw7AN1arUK8/1ml0ObhJm3wFkghIyJeyDew/13d5jl3v0+W7t4n QdpWF/gCpE4Grjc3IFz7lXR9B8jVIlY9BVVeL+VNzyCAqWEqNHHeoVpIX4qpldM/aNiA xKBCI3zWZdh3D/YWvYyeu51DtP4y0VlxFMFWi2FbagwzJz4fHuJ3GUK9WO3GQ/E5YvjY TowQ== X-Gm-Message-State: APjAAAUNWSq3KCqFuhkDl9DRJcGiRuaVsQzDGONEaGRwc8jy1ZURu7Gu /H4Z03DkEupinPXesGwobih/KYKGvQYJxQ== X-Google-Smtp-Source: APXvYqz5cKP3/ytl1ADTGEc581Sv6EuVrKN6C4XfooBe6Z/JdeCYdS4ENy8OHsdW1+Po1BRNT8iprQ== X-Received: by 2002:a81:7853:: with SMTP id t80mr73632878ywc.68.1578173135908; Sat, 04 Jan 2020 13:25:35 -0800 (PST) Received: from ?IPv6:2601:c0:c680:5cc0:1c3b:f16f:3708:29d8? ([2601:c0:c680:5cc0:1c3b:f16f:3708:29d8]) by smtp.gmail.com with ESMTPSA id l32sm25834629ywh.29.2020.01.04.13.25.35 (version=TLS1_2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Sat, 04 Jan 2020 13:25:35 -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: <7A150D33-2434-401B-B687-E74B6E0F0AF8@newclarity.net> Date: Sat, 4 Jan 2020 16:25:33 -0500 Cc: php internals Content-Transfer-Encoding: quoted-printable Message-ID: <21FF0232-D305-4E8F-9117-41D007E339D0@newclarity.net> References: <5e0d723f.1c69fb81.e2ae8.24e2SMTPIN_ADDED_MISSING@mx.google.com> <74F2DBFC-E63C-428C-A37F-2D0CEE15AD0F@newclarity.net> <70cbf5ab-2445-4003-987e-cb26301d64de@www.fastmail.com> <7A150D33-2434-401B-B687-E74B6E0F0AF8@newclarity.net> To: Larry Garfield 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 3, 2020, at 2:52 PM, Larry Garfield = wrote: >=20 > There's two broad reasons I think this is a bad idea. >=20 > 1) Constants are one thing. Function calls are another. They serve = different purposes. Trying to mutate them into one thing can only lead = to confusion and lack of understanding about what is actually going on. >=20 > 2) The approach you describe (of starting with constants everywhere = and refactoring to method calls later)... I would never do and do not = endorse. What you describe is basically "make globals nicer to work = with", whereas I am 100% firmly in the camp of "if I could remove = globals from the language entirely I would". Frankly, the use of = constants for configuration is an anti-pattern to begin with; they = should be used only for things that are truly constant. Honestly, I = cannot recall the last time I used constants for anything other than = giving some other compile-time value a nicer name. (Eg, = DEFAULT_THING_VALUE or giving nice names to bit flags or something like = that.) >=20 > For configuration, my answer is frankly "put your configuration behind = a nice configuration object from the very beginning and then you won't = have to refactor it later; Problem solved." You can use env vars for = configuration, and wrap those into a nice object, possibly using one of = the many DotEnv implementations that already exist to make them nicer to = work with in development. That is superior in basically every = conceivable way to semi-mutable globals passing themselves off as = pseudo-constants. >=20 > I *would* love to see property accessors come back, which would have a = side effect of making what you describe a little easier, but at no point = is it pretending to be a compile time value when it isn't. >=20 > --Larry Garfield So much to unpack here, but I will just hit the most important = points. You can say "Problem solved" but only because you redefined the problem = into an idealistically convenient use-case: 1. IF you have full control of all the code,=20 2. IF you are starting from scratch and do not have legacy code = to contend with,=20 3. And IF you and your team are not limited by budget, timeline = or developer skill. In the real world however you don't often get those ideal scenarios. It is irrelevant if you would never use constants or not endorse the = approach because many developers have used constants in the past and = continue to do so. I am proposing a solution to address a problem and = you are proposing idealogical purity.To give an analogy, it would be = like me asking Congress to address teen pregnancy and you being a = congressman who first spoke and said "Let's tell them not to have sex. = Problem solved." But we can argue *opinions* all day long. Let me provide some real-world = examples and some numbers. =20 Symfony =E2=80=94 which many PHP developers hold in high regard = including Drupal developers =E2=80=94 uses constants: = https://github.com/symfony/symfony/blob/master/src/Symfony/Bridge/Doctrine= /Tests/Form/Type/EntityTypeTest.php = https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Intl/= Locale/Locale.php = https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Intl/= DateFormatter/IntlDateFormatter.php = https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Workf= low/TransitionBlocker.php = https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Intl/= Intl.php = https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Secur= ity/Core/Security.php = https://github.com/symfony/symfony/blob/master/src/Symfony/Component/Seria= lizer/Normalizer/AbstractNormalizer.php On the other end of the spectrum are WordPress plugins. I maintain a = *somewhat* complete mirrors of the plugins database from WordPress.org = which I download from here http://plugins.svn.wordpress.org/.=20 I generated a list of `const =3D` found across all plugins = using this command: grep "const\s+[a-zA-Z1-9_]+\s*=3D" -RE --include \*.php . > const.txt This produced a file containing 455,068 constants. That's a lot of = constant usage for something you argue should never be done. Using this command I calculated that there were 338,520 constants that = were NOT integer or float. =20 cat const.txt | grep -E "=3D\s*-?\d+(\.\d+)?\s*;" | wc -l A lot of them (~20%?) were to create array keys that could be referenced = in a type-safe manner, e.g. from Guzzle: =46rom = 1-click-migration/vendor/guzzlehttp/guzzle/src/RequestOptions.php const ALLOW_REDIRECTS =3D 'allow_redirects'; const AUTH =3D 'auth'; const BODY =3D 'body'; const CERT =3D 'cert'; const COOKIES =3D 'cookies'; const CONNECT_TIMEOUT =3D 'connect_timeout'; const DEBUG =3D 'debug'; const DECODE_CONTENT =3D 'decode_content'; const DELAY =3D 'delay'; const EXPECT =3D 'expect'; const FORM_PARAMS =3D 'form_params'; const HEADERS =3D 'headers'; const HTTP_ERRORS =3D 'http_errors'; const JSON =3D 'json'; const MULTIPART =3D 'multipart'; const ON_HEADERS =3D 'on_headers'; const ON_STATS =3D 'on_stats'; const PROGRESS =3D 'progress'; const PROXY =3D 'proxy'; const QUERY =3D 'query'; const SINK =3D 'sink'; const SYNCHRONOUS =3D 'synchronous'; const SSL_KEY =3D 'ssl_key'; const STREAM =3D 'stream'; const VERIFY =3D 'verify'; const TIMEOUT =3D 'timeout'; const READ_TIMEOUT =3D 'read_timeout'; const VERSION =3D 'version'; const FORCE_IP_RESOLVE =3D 'force_ip_resolve'; Using this command I found that 17,908 constants were used to hardcode = URLs, one of the more frequent use-cases I am trying to address: cat const.txt | grep -E "https?://" | wc -l For just a few examples: =46rom = 1stpaygateway-for-woocommerce/includes/class-wc-gateway-1stpay.php =20 const URL_API =3D = "https://secure.1stpaygateway.net/secure/RestGW/Gateway/Transaction/"; const URL_API_VALIDATION =3D = 'https://secure-v.goemerchant.com/secure/RestGW/Gateway/Transaction/'; const URL_TRANS_CENTER_SUPPORT =3D = 'http://support.goemerchant.com/transaction-center.aspx'; const URL_GATEWAY_OPTIONS_SUPPORT =3D = "http://support.goemerchant.com/transaction-center.aspx?article=3Dgateway-= options"; const URL_SUBMIT_CC_BATCH_SUPPORT =3D = "http://support.goemerchant.com/transaction-center.aspx?article=3Dsubmit-c= redit-card-batch"; =46rom ad-kangaroo-for-adsense/google_api/Auth/OAuth2.php: =20 const OAUTH2_REVOKE_URI =3D = 'https://accounts.google.com/o/oauth2/revoke'; const OAUTH2_TOKEN_URI =3D = 'https://accounts.google.com/o/oauth2/token'; const OAUTH2_AUTH_URL =3D = 'https://accounts.google.com/o/oauth2/auth'; I scanned through the const.txt file with `less` for the non-numeric = constants using this command (of which there were 338,520): cat const.txt |grep -E -v "=3D\s*-?\d+(\.\d+)?\s*;" | less I anecdotally found constants used for the following use-case, many of = which are not "truly" constants and thus could benefit from being able = to be initialized in the future from a configuration source w/o breaking = any client code that used said constants: 1. SVG code for icons 2. Regular expressions (3989 uses where the constant contains = 'REGEX' in the name) 3. HTML snippets 4. CSS colors 5. XML Schema URLs and/or header elements=20 6. Error messages 7. User prompts 8. Date/Time formats 9. File extensions 10. Version numbers 11. WordPress Option names 12. Output formats (e.g. 'json', 'xml', 'csv', etc.) 13. Mustache/Handlebar templates 14. HTTP Extension Headers (e.g. "X-*") 15. Browser user-agent signatures 16. Payment processor codes 17. API/Server Error Codes 18. Bitmaps 19. HTTP verbs 20. GUIDs 21. HTML element mapping 22. Currency codes 23. PHP for eval()/code generation 24. UPS/Fedex codes 25. Relative API endpoints Those are just from "1"-"9" and "a"; there are probably another 10 or 20 = categories in "b" thru "z." Then using this command I calculated that there were 116,548 constants = that were integer or float. =20 cat const.txt | grep -E "=3D\s*-?\d+(\.\d+)?\s*;" | wc -l Most of those numeric constants would likely fit in your "truly" = constant category, but anecdotally a significant number would not; I = estimate ~5%, or ~5777.=20 For those that are not "true" constants, a developer might want to allow = an end user to configure them. But because they chose to hardcode as = constants initially the plugin can never evolve their code to allow for = configuration without making *breaking* changes. =20 For just a *few* examples: const RATIO =3D 0.5625; =20 const DEFAULT_FILE_UPLOAD_REQUEST_TIMEOUT =3D 3600; const MAX_LINE_LENGTH =3D 998; const AUTH_TOKEN_LIFETIME_SECS =3D 300; const CACHE_LIFETIME =3D 86400; const THUMB_WIDTH =3D 300; =09 const NUMBER_COLS_REPEATED_MAX =3D 1024; const COMPUTE_PING_CONNECTION_TIMEOUT_S =3D 0.5; =20 const DEFAULT_MEMSIZE =3D 10000; =09 const BATCH_WRITE_MAX_SIZE =3D 25; =20 const FILES_PER_CHUNK=3D600; const WRITE_INTERVAL =3D 10000; =09 const TIMEOUT_PRECISION =3D 0.2; const MIN_DURATION =3D 0.1; const MAX_DURATION =3D 15.0; const DEFAULT_CONCURRENCY =3D 5; Those constants came from these plugins, respectively: = accelerated-mobile-pages/includes/vendor/amp/includes/embeds/class-amp-you= tube-embed.php = accesspress-facebook-auto-post/api/facebook-mobile/Facebook/FacebookClient= .php acymailing/front/inc/phpmailer/phpmailer.php =09 ad-inserter/includes/google-api/Auth/OAuth2.php add-amazon-block/lib/amazonjs/amazonjs.php addon-library/inc_php/unitecreator_globals.class.php =09 = advanced-cf7-db/admin/class/PHPExcel/Writer/OpenDocument/Content.php = amazon-s3-and-cloudfront/vendor/Gcp/google/auth/src/Credentials/GCECredent= ials.php = amazon-s3-and-cloudfront/vendor/Gcp/google/auth/src/Cache/SysVCacheItemPoo= l.php =09 = amazon-s3-uploads/lib/aws-sdk-php/Aws/DynamoDb/Model/BatchRequest/WriteReq= uestBatchTransfer.php anybackup/includes/BitsBackupWorker.php = appilder-woocommerce-mobile-app-manager/inc/push-notification/ApnsPHP/Abst= ract.php =09 = assetsminify/vendor/symfony/process/Symfony/Component/Process/Process.php = auto-post-to-instagram/vendor/mgp25/instagram-php/src/Media/Constraints/Di= rectConstraints.php = auto-post-to-instagram/vendor/mgp25/instagram-php/src/Media/Constraints/Di= rectConstraints.php = aws-auto-ses/vendor/aws/aws-sdk-php/src/Multipart/AbstractUploader.php Note the above examples I give all started with "a." I did not give any = examples from "1" thru "9" and "b" thru "z" etc.: Anecdotally there was a dompdf package used by many plugins that makes = heavy use of constants for non "truly" constant values, e.g: =46rom = https://github.com/dompdf/dompdf/blob/master/src/FrameDecorator/ListBullet= .php const BULLET_PADDING =3D 1; // Distance from bullet to text in = pt const BULLET_THICKNESS =3D 0.04; // Thickness of bullet outline. = Screen: 0.08, print: better less, e.g. 0.04 const BULLET_DESCENT =3D 0.3; //descent of font below baseline. = Todo: Guessed for now. const BULLET_SIZE =3D 0.35; // bullet diameter. For now 0.5 of = font_size without descent. I think this analysis proves many PHP developers do use constants in = ways you claim you would never. IOW, the use-cases I am trying to = address exist to a significant degree in the wild. Further I believe I have made the case that there would be significant = value in allowing developers who previously used constants because of = prior lack of skill or too-tight timelines to be able to evolve their = code to initialize their constants with code instead of forcing their = users to change their code or worse. -Mike