Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:88276 Return-Path: Mailing-List: contact internals-help@lists.php.net; run by ezmlm Delivered-To: mailing list internals@lists.php.net Received: (qmail 85621 invoked from network); 17 Sep 2015 00:51:01 -0000 Received: from unknown (HELO lists.php.net) (127.0.0.1) by localhost with SMTP; 17 Sep 2015 00:51:01 -0000 Authentication-Results: pb1.pair.com smtp.mail=rewilliams@thesba.com; spf=pass; sender-id=pass Authentication-Results: pb1.pair.com header.from=rewilliams@thesba.com; sender-id=pass Received-SPF: pass (pb1.pair.com: domain thesba.com designates 208.106.205.210 as permitted sender) X-PHP-List-Original-Sender: rewilliams@thesba.com X-Host-Fingerprint: 208.106.205.210 ntsexchedgea1.newtekemail.com Received: from [208.106.205.210] ([208.106.205.210:57467] helo=NTSEXCHEDGEA1.nts.phx1) by pb1.pair.com (ecelerity 2.1.1.9-wez r(12769M)) with ESMTP id AA/68-41443-47E0AF55 for ; Wed, 16 Sep 2015 20:51:00 -0400 Received: from NTSMAILBOX2.NTS.PHX1 (208.106.205.233) by NTSEXCHEDGEA1.nts.phx1 (208.106.205.210) with Microsoft SMTP Server (TLS) id 15.0.847.32; Wed, 16 Sep 2015 17:50:41 -0700 Received: from NTSMAILBOX1.NTS.PHX1 (2002:d06a:cde8::d06a:cde8) by NTSMAILBOX2.NTS.PHX1 (2002:d06a:cde9::d06a:cde9) with Microsoft SMTP Server (TLS) id 15.0.847.32; Wed, 16 Sep 2015 17:50:31 -0700 Received: from NTSMAILBOX1.NTS.PHX1 ([fe80::51f0:160d:841f:d989]) by NTSMAILBOX1.NTS.PHX1 ([fe80::51f0:160d:841f:d989%13]) with mapi id 15.00.0847.030; Wed, 16 Sep 2015 17:50:31 -0700 To: Rowan Collins CC: "internals@lists.php.net" Thread-Topic: [PHP-DEV] PHP 7.1 - Address PHPSadness #28? Thread-Index: AQHQ36zP6Wb5e1HnokKnJlazAkejtZ4eJ62AgABxe4CAAAPLgIAAJlKAgAAUa4CAACGZAIAAGymAgAjS3QCAAJOjgIAA+D+AgAA5fACAB+afgIAB6WsAgAFo8ICAACyWAIAHac+AgAAGeYCAAD+qgIAAAnkAgABF9ACAAAG1gIAAJ92AgAAFuoCAADs0MIACTzKAgAA+UICAAApMAIAAHJoAgAAUVoCAAD3YAA== Date: Thu, 17 Sep 2015 00:50:31 +0000 Message-ID: <51FFBAEE-6433-49B5-A39E-FBBA47BA31DA@thesba.com> References: <1F615BCD-1B9B-4C51-A210-869F1AA1F6E3@craigfrancis.co.uk> <55E5EBBF.6020803@gmail.com> <0BA3A129-D356-4781-B6DE-E2B5A7924AE2@craigfrancis.co.uk> <55E6EC36.6090301@gmail.com> <9AF329EC-99A5-412D-A52B-432627A5520F@gmail.com> <6F4D91EE-B56E-4B83-B1AF-598C3F6897FC@craigfrancis.co.uk> <55F07BA4.2000204@gmail.com> <55F6B911.9080400@gmail.com> <96BE7F01-D04B-483B-B1A3-B45CED6DFCDC@craigfrancis.co.uk> <55F6F08C.1020506@gmail.com> <0BEF6D82-CB5F-49F6-A3A4-3267924A0CDA@thesba.com> <55F72CA9.2060301@gmail.com> <09369945-76FE-4E08-9C2C-15FB0577AD27@thesba.com> <55F752E7.9070801@gmail.com> <55F9747F.4070708@gmail.com> <738E9B97-6D20-4E37-85E0-994003ACDFC1@thesba.com> <55F9B168.9010007@gmail.com> <61163E50-AF39-4F69-B740-7F2D40129DB1@thesba.com> <8DB5E140-07D1-457D-AE32-F13D230E3CB3@gmail.com> In-Reply-To: <8DB5E140-07D1-457D-AE32-F13D230E3CB3@gmail.com> Accept-Language: en-US Content-Language: en-US X-MS-Has-Attach: yes X-MS-TNEF-Correlator: x-originating-ip: [172.16.153.36] Content-Type: multipart/signed; boundary="Apple-Mail=_D81C29F0-B291-475D-B792-1745DF0222F3"; protocol="application/pgp-signature"; micalg=pgp-sha512 MIME-Version: 1.0 Subject: Re: [PHP-DEV] PHP 7.1 - Address PHPSadness #28? From: rewilliams@thesba.com (Robert Williams) --Apple-Mail=_D81C29F0-B291-475D-B792-1745DF0222F3 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset=utf-8 On Sep 16, 2015, at 14:09, Rowan Collins = wrote: > I can certainly sympathise with wanting to run without any notices - = they are generally hints for writing better code. In the vast majority = of cases, though, that means working out *why* the variable is = undefined, otherwise you might as well just use the @ operator to say "I = don't care about this notice=E2=80=9D. Agree completely, and for that reason, we also ban @ except in those = rare cases where PHP forces the issue (that=E2=80=99s for other = discussions...). Indeed, this often comes up with short-lived issues = that are resolved quickly. For example, a config file is missing a = variable, so the user is told what it is, what kind of value to supply, = and they goes off to fix it, or the user is warned and the app goes on = with a default. But, all this happens without throwing errors and = without having to detour through the global error handler. In other = cases, the fix may not be so available, like with the template system = that creates variables in the view=E2=80=99s scope; here, the goal is = just to gracefully catch the condition and then define a default (and = maybe complain to the author). > This still implies that there's a common problem to fix, which I just = don't believe. The number of places where the following all hold true = must be vanishingly small: >=20 > - the third-party code is dumping bare variables into your scope = (globals, or a file-level include are the only mechanisms I can think = of) This seems to be pretty common with template systems, especially older = ones. It=E2=80=99s also common with config files. > - they do so unreliably, in the sense that different variables will be = set under different circumstances More common than different variables in different circumstances is the = missing variable. Consider the user who=E2=80=99s setting up an instance = of an application that uses a config file with bare variables =E2=80=94 = very easy to forget something, or type the name wrong, or whatever. Or = the programmer writing a plugin for a poorly documented application who = wants to be sure the runtime environment of the plugin is what=E2=80=99s = expected. Really, a lot of the same situations where one might need to = check the existence of an array element or object property, except that = the item to be checked happens to be a plain old variable. > - you/they have used null as a value which needs to be positively = asserted, not taken as the default state, so that isset() does not meet = your needs Well, it=E2=80=99s not so important that null represents a non-default = state, as that it represents any state. Often, null could just signal = that a default should be used, but with an existence check, the = programmer can be confidant that something/someone explicitly chose that = option. In the case of a config, for example, you can be sure the user = chose a particular value (which may be the default) versus having missed = it altogether. There are cases where that knowledge is very important to = safe programming. Consider that you=E2=80=99ve refactored a delete function to add support = for non-permanent deletion. You=E2=80=99ve done this by adding an = optional parameter: function DeleteFile($file, $permanentlyDelete =3D null) {} If $permanentlyDelete is null, the default action specified in a config = is used. The problem is, when the param is null, there=E2=80=99s no way = for the function to know for sure what the programmer of the caller = intended. There are two possibilities: 1 The programmer intentionally passed null because the config should be = used 2 The programmer forgot to consider that case after the refactor, so = null is automatically being used Ultimately, the function just follows orders, of course, but doing it = this way is dangerous because it=E2=80=99s all too easy to hit situation = 2, which means files could be permanently deleted in error. As the = programmer doing the refactor, it=E2=80=99s better to make the parameter = mandatory, which forces a revisit to every caller to make the = true/false/null decision explicit. In this case, the extra bit of intelligence comes from forcing the = caller to pass something. If the param is optional, we have no idea. = It=E2=80=99s the same thing with exists() on a variable: it gives us = extra intelligence about *why* a variable is null, whether it=E2=80=99s = because of an actual decision somewhere or because of an error or = oversight. And it provides that intelligence without fussing with PHP = errors. > - you have no way of presetting the variable to some other terminal = value to detect when it is explicitly set If the variables are injected before your code runs, it=E2=80=99s too = late. At that point, if you try to set a magic sentinel value, you=E2=80=99= re just overwriting the real value if there is one. It would work, = however, if you can pre-initialize before the injection: $foo =3D 'hope this gets overwritten'; require('/some/config.php'); if ($foo =3D=3D=3D 'hope this gets overwritten') { //uh-oh } I=E2=80=99m not really a fan of this pattern, though. If there=E2=80=99s = going to be a magic value to indicate that no better value was set, null = is the ideal choice: $foo =3D null; require('/some/config.php'); if ($foo =3D=3D=3D null) { //uh-oh } Here, we=E2=80=99ve used null exactly as intended. Unfortunately, this = breaks if null already has meaning, even if it's just "go with a = default=E2=80=9D. And, of course, it also throws the annoying undefined = error that we=E2=80=99re trying to avoid :-). This is where exists() comes in and cures all: require('/some/config.php'); if (!exists($foo)) { //uh-oh } It=E2=80=99s cleaner and shorter, but it also lets us again use null as = intended, rather than coming up with some whacky magic value that by = necessity is completely unrelated to the variable=E2=80=99s purpose yet = is hopefully understandable in meaning to future programmers passing = through (not *too* hard with a string, as above, but much tricker with = non-strings). >> In a dynamic >> language like PHP, I really don=E2=80=99t understand how folks can = *not* see >> that as an oversight. >=20 > I've not found evidence that any other language treats variables in = the proposed way, so it really doesn't feel like an "oversight" to me, = but a request for a new and quite unusual feature. In JavaScript, there=E2=80=99s this: if (typeof never_heard_of_me =3D=3D=3D 'undefined') { //uh-oh } albeit with a couple of minor caveats. > But yes, from a completeness point of view, it does make some sense. = My fear is that the people who don't understand why isset() does what it = does will think it's the answer to some imaginary problem, and end up = more confused than ever when their code breaks. Haven=E2=80=99t we already arrived here with isset() confusion? ;-) Seriously, I think updating the docs on the isset() page would help = mitigate this. =46rom this: "Determine if a variable is set and is not NULL. "If a variable has been unset with unset(), it will no longer be set. = isset() will return FALSE if testing a variable that has been set to = NULL. Also note that a null character ("\0") is not equivalent to the = PHP NULL constant." to something like this: "Determine if a variable exists in the current scope and is not NULL. To = test only whether a variable exists, use exists(). "If unset() is called on a variable, it will no longer exist. isset() = will return FALSE if testing a variable that has been set to NULL. Also = note that a null character ("\0") is not equivalent to the PHP NULL = constant." Obviously, other related pages could be updated similarly. > If the function had been proposed as a debugging aid, maybe filed = under Reflection or debug_variable_is_initialised, I might have more = sympathy, but that's not how it's been presented. Again, I don=E2=80=99t see this as something that directly controls = business logic. I see it as something that supports defensive = programming, improved error handling, and improved user experience. = Regardless, as we all know, every language feature can be abused, but = that doesn=E2=80=99t automatically mean we shouldn=E2=80=99t have those = features. Even something as widely derided as goto has its niche, after = all (albeit, a very, very small niche). In this case, not only is the = feature useful, but it nicely complements the array of related = functionality to provide a more complete feature set. -Bob --Apple-Mail=_D81C29F0-B291-475D-B792-1745DF0222F3 Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="signature.asc" Content-Type: application/pgp-signature; name="signature.asc" Content-Description: Message signed with OpenPGP using GPGMail -----BEGIN PGP SIGNATURE----- Comment: GPGTools - https://gpgtools.org iQIcBAEBCgAGBQJV+g5WAAoJEFBTSdRZ0ub3Y/UP/2PLAyRqTyTuugU1LKT9cezh PfXiZP6O6DE3aVVJhbj+VVbdPkNcZGZXt74nYurpSJDjpstXTQkn/0ol8+5GBog0 QPefSSuVxR2+eg8N5WjQioNYLRiYY5CdJv0AghbzpuE4R/n+Fw+0/tqnFJoqNisc RJmz0hL0kLgAOsb2seaIaPbUVElvJqzP/WFWtaCJRqFMnCJofzKvP85LKRNeGcxL 3CZNG4gM267YCMRSE8W5/+ryp+7+m0wJpS7MQbWtiH/isM8CM9LGW7EtX00fQ14y EIU2CjwWRJrb5z3CbwekeAnyCnH3bE2EEU8svVFE3Y/f4T07yUOjvhBwbB1vCE+C eVlyen7x8oT2UvnWcY+Jl3CAMsR7Nw33LbGi3ejk31EYFk73oE3ra+HyEZacO1Zj 57O+uGzvmzWyau2UixIbff0nUBNWxFTTbf/JXNxKRyAOX2GXfCk2BVor3z80hjjm UgqoDUmsWsbK3n//WLq8kyAVOLGXdZPYQvvFTXaFcGV4h3fslO1Sk8h9wmogqOWC OCpab08jcLMYw/cxdXJT1RpiWi2ccDk9FhBJ0QAUeJF63wYQJe5Mqg7NfEP5VUXP r4qrpa1FxugHJs0ZnwKGwhDrrTi3iHmxl4W69ZxFm6/GwkEJq44VmnQymYlOBPvs CzgoQ3mdDCGOqCUVR9M+ =VFQf -----END PGP SIGNATURE----- --Apple-Mail=_D81C29F0-B291-475D-B792-1745DF0222F3--