Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:127573 X-Original-To: internals@lists.php.net Delivered-To: internals@lists.php.net Received: from php-smtp4.php.net (php-smtp4.php.net [45.112.84.5]) by lists.php.net (Postfix) with ESMTPS id DBB991A00BC for ; Wed, 4 Jun 2025 03:43:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=php.net; s=mail; t=1749008458; bh=5bQNbC3sy9HkiofJuY1HzNjQG91MdI/dBwxXcHvE8HM=; h=References:In-Reply-To:From:Date:Subject:To:From; b=IHGwD0VkCyjoE6ltQ8bYXpGeB2yNYBBFwwfNKxsproeEo4WE2ulDoDpp5eIOKvMm1 dSAkqtpK5bahLWS+Ai0PHvBZOJk2mTcIQFWCgcNhKSGicAzsZB0HaLXsEjlE1i5/i/ g6EpkHjY3gT3pFsakO9X8fJAVnwV2JQhrjdZff0kRL0XNzZD3XuWqW6fPobUgXXZrd ttEYrC2Oi07MwsPVA27UM1o/+hpvBcdTcM8a7Ywa56LsmmoxX9aWCwnxdgZiNtY+c9 GMx9b0gyIeoY3smzvaO55cJFKof6u7njfZFZW+FNVc0LYvHWK2lsYDDOnSSsJ7ONWc i3sbiRiS9MUog== Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id A4A0318004C for ; Wed, 4 Jun 2025 03:40:57 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=0.9 required=5.0 tests=BAYES_20,DKIM_SIGNED, DKIM_VALID,DKIM_VALID_AU,DMARC_PASS,HEADER_FROM_DIFFERENT_DOMAINS, HTML_MESSAGE,RCVD_IN_DNSWL_NONE,RCVD_IN_MSPIKE_H3,RCVD_IN_MSPIKE_WL, SPF_HELO_NONE,SPF_PASS,T_REMOTE_IMAGE autolearn=no autolearn_force=no version=4.0.1 X-Spam-Virus: Error (Cannot connect to unix socket '/var/run/clamav/clamd.ctl': connect: Connection refused) X-Envelope-From: Received: from mail-qt1-f179.google.com (mail-qt1-f179.google.com [209.85.160.179]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by php-smtp4.php.net (Postfix) with ESMTPS for ; Wed, 4 Jun 2025 03:40:57 +0000 (UTC) Received: by mail-qt1-f179.google.com with SMTP id d75a77b69052e-4a5903bceffso25908751cf.3 for ; Tue, 03 Jun 2025 20:43:01 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=tithe.ly; s=google; t=1749008580; x=1749613380; darn=lists.php.net; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :from:to:cc:subject:date:message-id:reply-to; bh=5uE8lPV64FofW8cUhjcDBusS6F2t/ExfJi31w3K4rtw=; b=NaoO5oK2ZXcMas0nsLh7SIIiAcpS07PafsJ9W+EnEd1Hyodwa/727PXIXfspiK68IJ nG7GnErFDrtyzUYbOgnapydtXxDX/Bt56noEfZqz0R2hZ9AUexa/Uk/KyPNEnIZ/xJYA k0m73RdN8M86yoW4BTym5E1srV6KIZ4e3kyR0= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1749008580; x=1749613380; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=5uE8lPV64FofW8cUhjcDBusS6F2t/ExfJi31w3K4rtw=; b=g1I2Q8F4x/AdWBBg0O4b7T7WUO/ySWOfW749jjiiU1N+98TM+MfU5rAgqEptTQrgZ9 0RneBNdZT5RIHNx29aWdFq61V6DtSbjJfERHlO9mcARUK77BfyeqSvlXgHQNkjDlVyro m8NRRhV4CIH+8EzbU3BbvEoOTkUBaXrYxpCq3sFwLh8y9eofN8Jk5a9ZSYPRctuECspK foqCHIKMGtxz5ouC5mMRV0e4sRJB1ABnIba6SBDxr25DRhh397BsBcfdFcz0JSUmH9gc NBu58nIiknMERXMCsxqC5oTnFHVJQmRvXq12H5bDJeLpyegRjX2GpqhmTNsr+ONPMX2j eBfA== X-Gm-Message-State: AOJu0Yx+m5r5cEjrjYJf5mwy2SAq29jiZnhENDZ94R1GFvppKMVIyhoA kUJEgcy6vExKWhqpGmMnFFA1n/MqvK8Rx78jRcw599aD57IgVeCUcmIWkU49sDifjV+/X7Sr8Jl ZCu6BjpyV+9x0E8pt0KYLn6vxvFAsH2bWu8kyNQFvpCnye2iGhHWboQwI6A== X-Gm-Gg: ASbGncuIHRewy8t27GtiV1AZNopR/q3AVshB1nlFNo4FvKiFrD3rwx7u0ois0mgHFYJ Ljf365bbQZftQs5TXAdv8bAWc3QfBKPFC4FNILyC4NlHBr2o0yYeGWlQOTSqrOtRO9IwwWx6W7+ 9eTONZGoYO0coCK+Hcc+D6UXzeTdzd8+oLYss= X-Google-Smtp-Source: AGHT+IENb15cjasSCkGLfRVo4GsXkiu4IIKYgyTd6/uMXb+at26jQNnHcKm2PI2a/iNprDfQwnaZWo5uhJboVWwVJvw= X-Received: by 2002:a05:622a:480b:b0:4a3:6cbf:1fb7 with SMTP id d75a77b69052e-4a5a6878435mr18965431cf.20.1749008580389; Tue, 03 Jun 2025 20:43:00 -0700 (PDT) Precedence: bulk list-help: list-post: List-Id: internals.lists.php.net x-ms-reactions: disallow MIME-Version: 1.0 References: In-Reply-To: Date: Wed, 4 Jun 2025 13:42:23 +1000 X-Gm-Features: AX0GCFtBLCR5aD1dvcyHdQ4gdsi9Ba9AMYnCBagqHjXOk4oMyiZuNQWnIe7XDE8 Message-ID: Subject: Re: [PHP-DEV] Allowing class properties to remain Uninitialized as a default value. To: internals@lists.php.net Content-Type: multipart/alternative; boundary="00000000000024c5b10636b6cbb2" From: bradley.hayes@tithe.ly (Bradley Hayes) --00000000000024c5b10636b6cbb2 Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable Could be handy to allow this in normal functions too (but this it not the main use case and could be disallowed): public static function get(string $name, mixed $default =3D uninitialized):= string { $value =3D getenv($name); if ($value =3D=3D=3D false) { return $default; // throws uninitialized error. } return $value; } Not specifying a default value can now be done without creating a class or 'some highly specific string to avoid conflicts' to check for it just throws an error when it cant return a value. However, the uninitialized error is too generic for this situation and youd want a more specific error message. This would naturally make you think to check for uninitialized instead of using a try->catch block. To avoid treating it as a type of value with =3D=3D=3D a helper function could be provided changing the function like so: public static function get(string $name, mixed $default =3D uninitialized):= string { $value =3D getenv($name); if ($value =3D=3D=3D false) { if (isInitialized($default)) return $default; throw new \Exception("Environment variable '$name' not found."); } return $value; } On Tue, Jun 3, 2025 at 2:22=E2=80=AFPM Bradley Hayes wrote: > Uninitialized properties are really useful. > Being skipped in foreach loops and JSON encoded results and other > behaviours around uninitialized properties save a lot of time wasted on > basic checks and uncaught logical mistakes around null values. > > With the introduction of named arguments and promoted constructor > properties and read-only classes, it would be great to have the true > ability to not specify a value. > > class DTO { > public function __construct( > public string $id =3D uninitialized, > public string $name =3D uninitialized, > public null|int $age =3D uninitialized, > ) {} > } > > $dto =3D new DTO(id: 'someid', age: null); > if ($dto->age =3D=3D=3D null) echo "no age was given\n"; > echo $dto->name, PHP_EOL; // triggers the standard access before initial= isation error > > > EXAMPLE: A graphQL like API that only returns data that was asked for, is > serviced by a PHP class that only fetched the data that was asked for and > thus the DTO only has assigned values if they were fetched. > (These situations usually way more complex involving multiple SQL > joins/filters etc and nested objects/arrays in the return DTO). > > The DTO object has all the possible values defined on the class for type > safety and IDE indexing, but allows the uninitialized error to happen if > you try to use data that was never requested. > Uninitialized Errors when directly accessing a property that was not > assigned is also desirable as it indicates a logical error instead of > thinking the value is null. Null is considered a real value in the databa= se > in countless situations and API can assign null to delete a value from an > object. > > Additionally, since array unpacking now directly maps to named arguments = this would also save a ton of mapping code. > > *//array unpacking direct from the source > *$dto =3D new DTO( ...$sqlData); > > (FYI: SQL is way faster at mapping thousands of values to the naming > convention of the class than doing it in php so we do it in SQL. So yes w= e > would directly array unpack an sql result here.) > > I have is a discussion on this in github here: > https://github.com/php/php-src/issues/17771 > > The current workaround is to make the constructor take an array as its > only parameter and looping over it assigning matching array key values to > class properties and ignoring the rest. > > This works but breaks indexing and prevents the use of class inheritance > because not all the properties can be seen from the same scope forcing > every extender of the class to copy paste the constructor code from the > parent class. > > > -- > > Bradley Hayes / Engineer / TITHE.LY > > > > --=20 Bradley Hayes / Engineer / TITHE.LY --00000000000024c5b10636b6cbb2 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Could be handy to allow this =
in normal functions too (but this it not the main use case and could be dis=
allowed):
public static function =
get(string $name, m=
ixed $default =3D uninitialized): string
{
$value =3D getenv($name)
;
if ($value =3D=3D=3D false
) {
return $default; // throws uninitialized error.
}
return = $value;
} Not specifying a default value can now be done without creating a class or = 'some highly specific string to avoid conflicts' to check for it ju= st throws an error when it cant return a value.
However, the uninitialized error is too generic for this situ=
ation and youd want a more specific error message.
This would naturally make you think to check for uniniti=
alized instead of using a try->catch block.
To avoid treating it as a type of value with =3D=3D=3D a helpe=
r function could be provided changing the function like so:
public static func=
tion get<=
font color=3D"#000000" style=3D"font-size:9.8pt">(string $name, mixed $defau=
lt =3D uniniti=
alized): string
{
$value =3D getenv= ($name);
if (= $value =3D=3D=3D false) {
if = (isInitialized($default)) return
$default; throw new \Exception("Environment variable '$name' not found.");<= /span>
}
return $value;
<= /span>}

On Tue, Jun 3, 2025 at 2:22=E2=80= =AFPM Bradley Hayes <bradley.h= ayes@tithe.ly> wrote:
Uninitialized properties are really= useful.
Being skipped in foreach loops and JSON encoded results = and other behaviours around uninitialized properties save a lot of time was= ted on basic checks and uncaught logical mistakes around null values.
=

With the introduction of named arguments and promoted c= onstructor properties and read-only classes, it would be great to have=C2= =A0the true ability to not specify a value.
class DTO {
= public function __construct(
public string $id
=3D uninitialized,
public string $name =3D uninitialized,
publi= c null|int $age =3D uninitialized,
) {}
}

$dto =3D new DTO(id: 'some= id', age: null);
if ($dto->age =3D=3D=3D null) echo "no age was given\n"= ;;
echo $dto->name, PHP= _EOL; // tr= iggers the standard access before initialisation error

EXAMPLE: A graphQL like API that only returns= data that was asked for, is serviced by a PHP class that only fetched the = data that was asked for and thus the DTO only has assigned values if they w= ere fetched.
(These situations usually way more complex involving= multiple=C2=A0SQL joins/filters etc and nested objects/arrays in the retur= n DTO).

The DTO object has all the possible values= defined on the class for type safety and IDE indexing, but allows the unin= itialized error to happen if you try to use data that was never requested.<= /div>
Uninitialized Errors when directly accessing a property that= was not assigned is also desirable as it indicates a logical error instead= of thinking the value is null. Null is considered a real value in the data= base in countless situations and API can assign null to delete a value from= an object.
Additionally, since array unpacking now directly maps to named argum=
ents this would also save a ton of mapping code.
<= div>
//array unpacking direct from=
 the source
$dto =3D new DTO( ...$sqlData);<=
/pre>
(FYI: SQL is way faster at mapping thousa= nds of values to the naming convention of the class than doing it in php so= we do it in SQL. So yes we would directly array unpack an sql result here.= )

I have is a discussion on this in github here:

The current workaround is to make the constructor take an array as it= s only parameter and looping over it assigning matching array key values to= class properties and ignoring the rest.

This work= s but breaks indexing and prevents the use of class inheritance because not= all the properties can be seen from the same scope forcing every extender = of the class to copy paste the constructor code from the parent class.


<= span class=3D"gmail_signature_prefix">--

Bradley= Hayes / Engineer / TITHE.LY


<= /span>


--
--00000000000024c5b10636b6cbb2--