Re: [PHP-DEV] Undefined variables and the array append operator
On 30/03/2022 15:32, Guilliam Xavier wrote: On the other hand, I agree that `$undefined[] = $x` looks like a bug... are both cases the exact same opcode? Some very good points raised in this thread about how many different closely-related cases there are here. I shall have to think clearly about which cases we want to change, and look at the implementation to see how easily those can be separated out from the others. It sounds like there are at least some cases that might pass an RFC vote to change, though. Regards, -- Rowan Tommins [IMSoP] -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: https://www.php.net/unsub.php
Re: [PHP-DEV] Undefined variables and the array append operator
On Wed, 30 Mar 2022 at 15:33, Guilliam Xavier wrote: > Not really a "compelling reason why we should keep this inconsistency", but > I have occasionally relied on array autovivification *for sub-dimensions*, > I rely on this often when remapping data for analysis. These scripts are run a handful of times and discarded. Autovivication keeps the code short. Here's a snippet I wrote yesterday: $out = []; while ($row = $res->fetchAssociative()) { // ... $docId = $row['document_id']; if (!isset($out[$docId])) { $out[$docId] = [ 'application_id' => $row['application_id'], 'document_id' => $docId, 'filename' => $row['filename'], ]; } $out[$docId]['labels'][$row['document_rejection_reason_id']] = true; } Naturally I would prefer to keep this behaviour for arrays. Peter
Re: [PHP-DEV] Typed constants revisited
> Ah yes, I hadn't considered expanding this RFC to namespaced and global > constants. Let me mull over implementation syntax for those and include > them in the RFC. My initial reaction is to not include those in this RFC, > keeping the scope to just class constants. If there is value in typing > namespaced and global constants, then another RFC could add those. > Yes, it could be simply a mention in a "Future scope" (or even "Unaffected functionality") section (and the syntax could indeed be a problem, like for typed local/global variables...) > Once I have all these new issues figured out and the RFC updated, I'll > start that new thread. > Looking forward to it =)
Re: [PHP-DEV] Typed constants revisited
Guilliam, On Wed, Mar 30, 2022 at 7:50 AM Guilliam Xavier wrote: > Hi Mark, > > I have updated the RFC https://wiki.php.net/rfc/typed_class_constants with more details and examples from this thread, and updated the RFC status to Under Discussion. Hopefully the updated RFC helps answer questions and clarifies what the proposal includes. >>> > Thanks (I assume that you talked with the original author) -- not sure if > you should have started a new thread with the "[RFC]" tag in the subject? > I will address the issues from you and Alex in the RFC page, then start a new thread with "[RFC]" since you are correct this has moved past initial testing-the-waters and is now into the discussion phase about the RFC. I reached out multiple times to the original author but have not received a response. I did leave Benas as an author to give him credit for the work he did. > > >> I think you should also update the "Supported types" section. >>> Starting with enums, constants can also be objects. Once a good >>> technical solution is found, any object would be supported probably >>> https://wiki.php.net/rfc/new_in_initializers#future_scope >>> I think that only void, never and callable types should not be >>> supported, just like on properties. >>> >> >> I have updated the "Supported types" to list out all types that are >> supported and which types are not supported. >> > > A few comments, by subsection: > > - **Supported types**: This corresponds to the types currently allowed > for const values (as well as unions thereof) except it [still] doesn't > mention enums (which internally are classes implementing the `UnitEnum` > interface, and whose values are ultimately of `object` type) although > currently allowed. It also doesn't mention `mixed` (used later in examples). > - **Strict and coercive typing modes**: I didn't understand it on first > read; I had to read the later "Constant values" section and compare both > with > https://wiki.php.net/rfc/typed_properties_v2#strict_and_coercive_typing_modes > and https://wiki.php.net/rfc/typed_properties_v2#default_values > - **Inheritance and variance**: Several occurrences of "Class constants" > should probably be "*Typed* class constants". Also, I still think that > `protected bool $isExtinct` is *not* a good parallel to `public const bool > CAN_FLY` (see my previous message). > - **Constant values**: You should probably remove the `iterable` example > now [and maybe add an `enum` one]. > Thanks for the input, I'll work on addressing those. > > >> Constants cannot be objects since objects are mutable, so typed constants >> will not be allowed to be an enum (which is technically an object). A typed >> constant _may_ be an enum value though, so the following example will be >> valid: >> >> ``` >> enum Fruit >> { >> case Apple; >> case Banana; >> } >> >> class Colors >> { >> protected const string RED = Fruit::Apple; >> protected const string YELLOW = Fruit::Banana; >> } >> ``` >> > > This is incorrect, `Fruit::Apple` is of type `Fruit` (ultimately > `object`), not `string`. But it is *not* mutable, and *is* allowed as a > const value currently. > Yes, Alex also identified this issue in my examples, I will correct that and include enum examples in an updated RFC. I will do that before starting an "[RFC]" thread. > > Besides, I realized that the RFC is [only] for *class* constants; what > about *namespaced (and global)* constants? > Ah yes, I hadn't considered expanding this RFC to namespaced and global constants. Let me mull over implementation syntax for those and include them in the RFC. My initial reaction is to not include those in this RFC, keeping the scope to just class constants. If there is value in typing namespaced and global constants, then another RFC could add those. Once I have all these new issues figured out and the RFC updated, I'll start that new thread. > > Regards, > > -- > Guilliam Xavier >
Re: [PHP-DEV] Undefined variables and the array append operator
Hi Rowan, Not really a "compelling reason why we should keep this inconsistency", but I have occasionally relied on array autovivification *for sub-dimensions*, e.g.: ``` function f(iterable $xs) { $map = []; // initialization! foreach ($xs as $x) { // $map[foo($x)] ??= []; not needed $map[foo($x)][] = bar($x); // autovivification } // Then e.g.: foreach ($map as $foo => $bars) { foreach ($bars as $bar) { /* ... */ } } } ``` (adapted from my https://externals.io/message/114595#114611 message in the "Disable autovivification on false" thread). On the other hand, I agree that `$undefined[] = $x` looks like a bug... are both cases the exact same opcode? (if yes, I wouldn't really mind updating my code, especially for consistency with other "append" operators like .= or +=, and that could even be an opportunity to rewrite it in a more "functional" style...) Regards, -- Guilliam Xavier
Re: [PHP-DEV] Undefined variables and the array append operator
On Wed, Mar 30, 2022, at 9:11 AM, Claude Pache wrote: >> Le 29 mars 2022 à 21:44, Rowan Tommins a écrit : >> >> Hi all, >> >> If $foo is not defined, statements such as $foo += 1 and $foo .= 'blah' >> raise "undefined variable" Warnings in PHP 8, and will throw Errors in PHP >> 9. However, the very similar looking $foo[] = 1 succeeds silently. >> >> This seems odd to me, as "append to string" and "append to array" seem like >> very similar operations, with most of the same use cases and possible bugs. >> >> > > > Hi, > > There are various subcases to consider: > > (1) $x[] = 42; and $x['y'] = 42; where $x is undefined > > (2) $x[] = 42; and $x['y'] = 42; where $x is null > > (3) $x['y'][] = 42; and $x['y']['w'] = 42; where $x is an array, and > $x['y'] is undefined. > > Of course, I agree that (1) should be an error. > > The case (3) is similar to (1), but I think it is more controversial to > change. I bet that they are various places in my code that take > advantage of that feature, although personally I don’t mind to write > $x['y'] ??= [ ]; when needed. We should probably also consider if there are other places where we're comfortable with ??= working correctly. I'm not sure off hand if it should be acceptable in 1 or 2, but it's a question we should think through and document decisions on. --Larry Garfield -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: https://www.php.net/unsub.php
Re: [PHP-DEV] Typed constants revisited
Alex, On Wed, Mar 30, 2022 at 7:47 AM Alexandru Pătrănescu wrote: > Hey Mark, > > On Wed, Mar 30, 2022 at 4:01 PM Mark Niebergall > wrote: > >> Alex, >> >> On Tue, Mar 29, 2022 at 10:35 PM Alexandru Pătrănescu >> wrote: >> >>> Hey Mark, >>> >>> >>> On Wed, Mar 30, 2022 at 6:03 AM Mark Niebergall >>> wrote: >>> I have updated the RFC https://wiki.php.net/rfc/typed_class_constants with more details and examples from this thread, and updated the RFC status to Under Discussion. Hopefully the updated RFC helps answer questions and clarifies what the proposal includes. >>> >>> Thanks for the RFC and the drive here. >>> I personally see the benefit and I think it would be a nice addition. >>> >>> I think you should also update the "Supported types" section. >>> Starting with enums, constants can also be objects. Once a good >>> technical solution is found, any object would be supported probably >>> https://wiki.php.net/rfc/new_in_initializers#future_scope >>> I think that only void, never and callable types should not be >>> supported, just like on properties. >>> >>> >> I have updated the "Supported types" to list out all types that are >> supported and which types are not supported. >> >> Constants cannot be objects since objects are mutable, so typed constants >> will not be allowed to be an enum (which is technically an object). A typed >> constant _may_ be an enum value though, so the following example will be >> valid: >> >> ``` >> enum Fruit >> { >> case Apple; >> case Banana; >> } >> >> class Colors >> { >> protected const string RED = Fruit::Apple; >> protected const string YELLOW = Fruit::Banana; >> } >> ``` >> > > Actually, Fruit::Apple is an enum instance and that is an object that is > of Fruit enum type (Fruit class). > You can check this as it's already possible in PHP 8.1, even if it's not > yet possible to have them with type: https://3v4l.org/f4WIC > > What you are referring to as enum value is actually a backed value for an > enum instance. > If you would define the enum as > ``` > enum Fruit: string > { > case Apple = 'apple'; > case Banana = 'banana'; > } > ``` > You could obtain the value with Fruit::Apple->value. But I'm not > referring to this. > > So going back to the topic I mentioned, a constant can right now be an > object. > It can be only an enum instance for now but I believe that in the near > future we will be able to have any object there. > Ah yes, you are correct, my mistake. I will need to make some more updates to the RFC page to address that. > > Also, self and parent would make sense for valid typed constants, just > like they do work on properties. > I'll add examples and an item about this as well. > > Regards, > Alex > > >> >>> Of note is the "Inheritance and variance" section, which details uses with abstracts and interfaces, plus the "Constant values" section which includes details about errors. > > -- > Guilliam Xavier > >>> >>> Thanks, >>> Alex >>> >>
Re: [PHP-DEV] Undefined variables and the array append operator
> Le 29 mars 2022 à 21:44, Rowan Tommins a écrit : > > Hi all, > > If $foo is not defined, statements such as $foo += 1 and $foo .= 'blah' raise > "undefined variable" Warnings in PHP 8, and will throw Errors in PHP 9. > However, the very similar looking $foo[] = 1 succeeds silently. > > This seems odd to me, as "append to string" and "append to array" seem like > very similar operations, with most of the same use cases and possible bugs. > > Hi, There are various subcases to consider: (1) $x[] = 42; and $x['y'] = 42; where $x is undefined (2) $x[] = 42; and $x['y'] = 42; where $x is null (3) $x['y'][] = 42; and $x['y']['w'] = 42; where $x is an array, and $x['y'] is undefined. Of course, I agree that (1) should be an error. The case (3) is similar to (1), but I think it is more controversial to change. I bet that they are various places in my code that take advantage of that feature, although personally I don’t mind to write $x['y'] ??= [ ]; when needed. —Claude -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: https://www.php.net/unsub.php
Re: [PHP-DEV] Typed constants revisited
Hi Mark, I have updated the RFC https://wiki.php.net/rfc/typed_class_constants with >>> more details and examples from this thread, and updated the RFC status to >>> Under Discussion. Hopefully the updated RFC helps answer questions and >>> clarifies what the proposal includes. >>> >> Thanks (I assume that you talked with the original author) -- not sure if you should have started a new thread with the "[RFC]" tag in the subject? > I think you should also update the "Supported types" section. >> Starting with enums, constants can also be objects. Once a good technical >> solution is found, any object would be supported probably >> https://wiki.php.net/rfc/new_in_initializers#future_scope >> I think that only void, never and callable types should not be supported, >> just like on properties. >> > > I have updated the "Supported types" to list out all types that are > supported and which types are not supported. > A few comments, by subsection: - **Supported types**: This corresponds to the types currently allowed for const values (as well as unions thereof) except it [still] doesn't mention enums (which internally are classes implementing the `UnitEnum` interface, and whose values are ultimately of `object` type) although currently allowed. It also doesn't mention `mixed` (used later in examples). - **Strict and coercive typing modes**: I didn't understand it on first read; I had to read the later "Constant values" section and compare both with https://wiki.php.net/rfc/typed_properties_v2#strict_and_coercive_typing_modes and https://wiki.php.net/rfc/typed_properties_v2#default_values - **Inheritance and variance**: Several occurrences of "Class constants" should probably be "*Typed* class constants". Also, I still think that `protected bool $isExtinct` is *not* a good parallel to `public const bool CAN_FLY` (see my previous message). - **Constant values**: You should probably remove the `iterable` example now [and maybe add an `enum` one]. > Constants cannot be objects since objects are mutable, so typed constants > will not be allowed to be an enum (which is technically an object). A typed > constant _may_ be an enum value though, so the following example will be > valid: > > ``` > enum Fruit > { > case Apple; > case Banana; > } > > class Colors > { > protected const string RED = Fruit::Apple; > protected const string YELLOW = Fruit::Banana; > } > ``` > This is incorrect, `Fruit::Apple` is of type `Fruit` (ultimately `object`), not `string`. But it is *not* mutable, and *is* allowed as a const value currently. Besides, I realized that the RFC is [only] for *class* constants; what about *namespaced (and global)* constants? Regards, -- Guilliam Xavier
Re: [PHP-DEV] Typed constants revisited
Hey Mark, On Wed, Mar 30, 2022 at 4:01 PM Mark Niebergall wrote: > Alex, > > On Tue, Mar 29, 2022 at 10:35 PM Alexandru Pătrănescu > wrote: > >> Hey Mark, >> >> >> On Wed, Mar 30, 2022 at 6:03 AM Mark Niebergall >> wrote: >> >>> >>> I have updated the RFC https://wiki.php.net/rfc/typed_class_constants >>> with >>> more details and examples from this thread, and updated the RFC status to >>> Under Discussion. Hopefully the updated RFC helps answer questions and >>> clarifies what the proposal includes. >>> >> >> Thanks for the RFC and the drive here. >> I personally see the benefit and I think it would be a nice addition. >> >> I think you should also update the "Supported types" section. >> Starting with enums, constants can also be objects. Once a good technical >> solution is found, any object would be supported probably >> https://wiki.php.net/rfc/new_in_initializers#future_scope >> I think that only void, never and callable types should not be supported, >> just like on properties. >> >> > I have updated the "Supported types" to list out all types that are > supported and which types are not supported. > > Constants cannot be objects since objects are mutable, so typed constants > will not be allowed to be an enum (which is technically an object). A typed > constant _may_ be an enum value though, so the following example will be > valid: > > ``` > enum Fruit > { > case Apple; > case Banana; > } > > class Colors > { > protected const string RED = Fruit::Apple; > protected const string YELLOW = Fruit::Banana; > } > ``` > Actually, Fruit::Apple is an enum instance and that is an object that is of Fruit enum type (Fruit class). You can check this as it's already possible in PHP 8.1, even if it's not yet possible to have them with type: https://3v4l.org/f4WIC What you are referring to as enum value is actually a backed value for an enum instance. If you would define the enum as ``` enum Fruit: string { case Apple = 'apple'; case Banana = 'banana'; } ``` You could obtain the value with Fruit::Apple->value. But I'm not referring to this. So going back to the topic I mentioned, a constant can right now be an object. It can be only an enum instance for now but I believe that in the near future we will be able to have any object there. Also, self and parent would make sense for valid typed constants, just like they do work on properties. Regards, Alex > >> >>> Of note is the "Inheritance and variance" section, which details uses >>> with >>> abstracts and interfaces, plus the "Constant values" section which >>> includes >>> details about errors. >>> >>> >>> > >>> > -- >>> > Guilliam Xavier >>> > >>> >> >> Thanks, >> Alex >> >
Re: [PHP-DEV] Typed constants revisited
Alex, On Tue, Mar 29, 2022 at 10:35 PM Alexandru Pătrănescu wrote: > Hey Mark, > > > On Wed, Mar 30, 2022 at 6:03 AM Mark Niebergall > wrote: > >> >> I have updated the RFC https://wiki.php.net/rfc/typed_class_constants >> with >> more details and examples from this thread, and updated the RFC status to >> Under Discussion. Hopefully the updated RFC helps answer questions and >> clarifies what the proposal includes. >> > > Thanks for the RFC and the drive here. > I personally see the benefit and I think it would be a nice addition. > > I think you should also update the "Supported types" section. > Starting with enums, constants can also be objects. Once a good technical > solution is found, any object would be supported probably > https://wiki.php.net/rfc/new_in_initializers#future_scope > I think that only void, never and callable types should not be supported, > just like on properties. > > I have updated the "Supported types" to list out all types that are supported and which types are not supported. Constants cannot be objects since objects are mutable, so typed constants will not be allowed to be an enum (which is technically an object). A typed constant _may_ be an enum value though, so the following example will be valid: ``` enum Fruit { case Apple; case Banana; } class Colors { protected const string RED = Fruit::Apple; protected const string YELLOW = Fruit::Banana; } ``` > >> Of note is the "Inheritance and variance" section, which details uses with >> abstracts and interfaces, plus the "Constant values" section which >> includes >> details about errors. >> >> >> > >> > -- >> > Guilliam Xavier >> > >> > > Thanks, > Alex >
Re: [PHP-DEV] Re: Undefined variables and the array append operator
> RFC. There are other inconsistencies as well now, depending on how the undefined variable comes to exist absolutely, but shouldn't try to do too much in a single rfc, wouldn't want it to be rejected for the wrong reasons ^^ On Wed, 30 Mar 2022 at 12:17, Björn Larsson via internals < internals@lists.php.net> wrote: > Den 2022-03-29 kl. 21:44, skrev Rowan Tommins: > > Hi all, > > > > If $foo is not defined, statements such as $foo += 1 and $foo .= 'blah' > > raise "undefined variable" Warnings in PHP 8, and will throw Errors in > > PHP 9. However, the very similar looking $foo[] = 1 succeeds silently. > > > > This seems odd to me, as "append to string" and "append to array" seem > > like very similar operations, with most of the same use cases and > > possible bugs. > > > > > > From an *implementation* point of view, this is presumably because they > > are defined as different Op Codes - ASSIGN_OP for .= and ASSIGN_DIM for > > []=, I believe. But that doesn't explain *why* ASSIGN_DIM behaves this > way. > > > > A *historical* explanation might relate to Perl's "autovivification" > > feature. However, PHP does *not* implement the same rules as Perl: for > > instance, Perl will create array dimensions just by reading them, which > > PHP does not; and Perl has a completely different type system, with > > cases like "a scalar becomes a reference to a hash unless already a > > reference to a list". Note also that I'm *not* talking about > > multi-dimensional arrays with missing keys here, only undefined local > > variables, as were the subject of the recent RFC. > > > > The *observable behaviour* for most operators in PHP is the same: > > > > 1) if the variable is undefined, consider the value to be null > > 2) coerce the value to the appropriate type; if the value is null, this > > gives the relevant "empty" value, such as '', 0, or [] > > 3) apply the operator > > > > There isn't anything particularly special with $foo[] = 'bar' in this > > case, except that it's the only operator that doesn't raise a Warning > > (and planned Error) at step 1. The same goes for all the other uses of > > the [] syntax I can think of, like $foo['key'] = 'bar', or $ref =& > $foo[]. > > > > > > For example, consider the following simple validation code > > [https://3v4l.org/pP5CU]: > > > > $requiredFields = ['name', 'age', 'hair_colour']; > > > > // Note: $errorString is not initialised > > foreach ( $requiredFields as $field ) { > > if ( ! isset($_POST[$field]) ) { > > $errorString .= "Missing required field '$field'. "; > > } > > } > > echo $errorString; > > > > This gives an "Undefined variable" Notice / Warning / Error, depending > > on the version. That's reasonable, as failing to initialise $errorString > > might cause problems if this code is integrated into a loop or larger > > function later. > > > > However, switch the code from building up a string to building up an > > array, and the result is identical, but the Notice / Warning / Error > > goes away [https://3v4l.org/ojZ1O]: > > > > // Note: $errorArray is not initialised > > foreach ( $requiredFields as $field ) { > > if ( ! isset($_POST[$field]) ) { > > $errorArray[] = "Missing required field '$field'. "; > > } > > } > > echo implode('', $errorArray); > > > > > > Can anyone give a compelling reason why we should keep this > > inconsistency, or should I raise an RFC to bring it in line with other > > undefined variable accesses? > > > > > I think it deserves an RFC. Then we also capture your excellent > explanation above! > > Regards //Björn L > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php > >
[PHP-DEV] Re: Undefined variables and the array append operator
Den 2022-03-29 kl. 21:44, skrev Rowan Tommins: Hi all, If $foo is not defined, statements such as $foo += 1 and $foo .= 'blah' raise "undefined variable" Warnings in PHP 8, and will throw Errors in PHP 9. However, the very similar looking $foo[] = 1 succeeds silently. This seems odd to me, as "append to string" and "append to array" seem like very similar operations, with most of the same use cases and possible bugs. From an *implementation* point of view, this is presumably because they are defined as different Op Codes - ASSIGN_OP for .= and ASSIGN_DIM for []=, I believe. But that doesn't explain *why* ASSIGN_DIM behaves this way. A *historical* explanation might relate to Perl's "autovivification" feature. However, PHP does *not* implement the same rules as Perl: for instance, Perl will create array dimensions just by reading them, which PHP does not; and Perl has a completely different type system, with cases like "a scalar becomes a reference to a hash unless already a reference to a list". Note also that I'm *not* talking about multi-dimensional arrays with missing keys here, only undefined local variables, as were the subject of the recent RFC. The *observable behaviour* for most operators in PHP is the same: 1) if the variable is undefined, consider the value to be null 2) coerce the value to the appropriate type; if the value is null, this gives the relevant "empty" value, such as '', 0, or [] 3) apply the operator There isn't anything particularly special with $foo[] = 'bar' in this case, except that it's the only operator that doesn't raise a Warning (and planned Error) at step 1. The same goes for all the other uses of the [] syntax I can think of, like $foo['key'] = 'bar', or $ref =& $foo[]. For example, consider the following simple validation code [https://3v4l.org/pP5CU]: $requiredFields = ['name', 'age', 'hair_colour']; // Note: $errorString is not initialised foreach ( $requiredFields as $field ) { if ( ! isset($_POST[$field]) ) { $errorString .= "Missing required field '$field'. "; } } echo $errorString; This gives an "Undefined variable" Notice / Warning / Error, depending on the version. That's reasonable, as failing to initialise $errorString might cause problems if this code is integrated into a loop or larger function later. However, switch the code from building up a string to building up an array, and the result is identical, but the Notice / Warning / Error goes away [https://3v4l.org/ojZ1O]: // Note: $errorArray is not initialised foreach ( $requiredFields as $field ) { if ( ! isset($_POST[$field]) ) { $errorArray[] = "Missing required field '$field'. "; } } echo implode('', $errorArray); Can anyone give a compelling reason why we should keep this inconsistency, or should I raise an RFC to bring it in line with other undefined variable accesses? I think it deserves an RFC. Then we also capture your excellent explanation above! Regards //Björn L -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: https://www.php.net/unsub.php
[PHP-DEV] ZEND_VM_HOT is ZEND_COLD?
Dear PHP Internals, I am looking at zend_vm_execute.h file and found some lines of code which I do not quite get. Who can help tell that why we should have ZEND_COLD attribute in ZEND_VM_HOT line definition, or I can simply ignore it as it is trivial? Thanks. # if (ZEND_VM_KIND == ZEND_VM_KIND_HYBRID) // # define ZEND_COLD __attribute__((cold)) # define ZEND_VM_HOT zend_always_inline ZEND_COLD ZEND_OPT_SIZE # define ZEND_VM_COLDZEND_COLD ZEND_OPT_SIZE Here is one use of this macro in function declaration. static ZEND_VM_HOT ZEND_OPCODE_HANDLER_RET ZEND_FASTCALL ZEND_JMP_SPEC_HANDLER(ZEND_OPCODE_HANDLER_ARGS) === Tony Su (Su, Tao) make a 'lazy' programmer diligently with efficiency
Re: [PHP-DEV] Undefined variables and the array append operator
On Tue, Mar 29, 2022 at 9:44 PM Rowan Tommins wrote: > > Hi all, > > If $foo is not defined, statements such as $foo += 1 and $foo .= 'blah' > raise "undefined variable" Warnings in PHP 8, and will throw Errors in > PHP 9. However, the very similar looking $foo[] = 1 succeeds silently. > > This seems odd to me, as "append to string" and "append to array" seem > like very similar operations, with most of the same use cases and > possible bugs. > > > From an *implementation* point of view, this is presumably because they > are defined as different Op Codes - ASSIGN_OP for .= and ASSIGN_DIM for > []=, I believe. But that doesn't explain *why* ASSIGN_DIM behaves this way. > > A *historical* explanation might relate to Perl's "autovivification" > feature. However, PHP does *not* implement the same rules as Perl: for > instance, Perl will create array dimensions just by reading them, which > PHP does not; and Perl has a completely different type system, with > cases like "a scalar becomes a reference to a hash unless already a > reference to a list". Note also that I'm *not* talking about > multi-dimensional arrays with missing keys here, only undefined local > variables, as were the subject of the recent RFC. > > The *observable behaviour* for most operators in PHP is the same: > > 1) if the variable is undefined, consider the value to be null > 2) coerce the value to the appropriate type; if the value is null, this > gives the relevant "empty" value, such as '', 0, or [] > 3) apply the operator > > There isn't anything particularly special with $foo[] = 'bar' in this > case, except that it's the only operator that doesn't raise a Warning > (and planned Error) at step 1. The same goes for all the other uses of > the [] syntax I can think of, like $foo['key'] = 'bar', or $ref =& $foo[]. > > > For example, consider the following simple validation code > [https://3v4l.org/pP5CU]: > > $requiredFields = ['name', 'age', 'hair_colour']; > > // Note: $errorString is not initialised > foreach ( $requiredFields as $field ) { > if ( ! isset($_POST[$field]) ) { > $errorString .= "Missing required field '$field'. "; > } > } > echo $errorString; > > This gives an "Undefined variable" Notice / Warning / Error, depending > on the version. That's reasonable, as failing to initialise $errorString > might cause problems if this code is integrated into a loop or larger > function later. > > However, switch the code from building up a string to building up an > array, and the result is identical, but the Notice / Warning / Error > goes away [https://3v4l.org/ojZ1O]: > > // Note: $errorArray is not initialised > foreach ( $requiredFields as $field ) { > if ( ! isset($_POST[$field]) ) { > $errorArray[] = "Missing required field '$field'. "; > } > } > echo implode('', $errorArray); > > > Can anyone give a compelling reason why we should keep this > inconsistency, or should I raise an RFC to bring it in line with other > undefined variable accesses? > > > Regards, > > -- > Rowan Tommins > [IMSoP] > > -- > PHP Internals - PHP Runtime Development Mailing List > To unsubscribe, visit: https://www.php.net/unsub.php > I think it's worth raising an RFC. There are other inconsistencies as well now, depending on how the undefined variable comes to exist, particularly around arrays. For example: $x = null; $a = $x['nope']; echo $a; There should be an error here, but $a gets the value null and only a warning is issued. Yet, this is already an error: $x = new class { public string|null $nope; }; $a = $x->nope; echo $a; So, depending on how you json_decode() you may or may not have issues. -- PHP Internals - PHP Runtime Development Mailing List To unsubscribe, visit: https://www.php.net/unsub.php