Re: [PHP-DEV] Basic Type Alias

2023-10-29 Thread Jorg Sowa
I really like the idea and I would love to see it in PHP. I'm wondering
however, what would be the scope of the feature and how complex would be
designed type system. Examples I saw in this thread could be easily
replaced with union and intersection types (i.e. numeric as int|float). In
my opinion, there is a little benefit implementing in this shape making the
PHP core more complex.

The two use cases of user defined types in PHP which would benefit a lot
IMO, would be:
1. Typed arrays similar to Typescript.
2. Semantic types which would increase the security of systems. Example:
type UserId = int;

function setUserId_1(int $userId){}

function setUserId_2(UserId $userId){}

setUserId_1(5); // OK
setUserId_2(5); // TypeError

setUserId_1(UserId(5)); // OK
setUserId_2(UserId(5)); // OK

Kind regards,
Jorg


Re: [PHP-DEV] Re: Basic Type Alias

2023-10-29 Thread Robert Landers
On Sat, Oct 28, 2023 at 10:29 PM Alexandru Pătrănescu
 wrote:
>
> Hey,
>
> So actually while reading this:
>
> On Fri, Oct 27, 2023 at 11:42 PM Oladoyinbo Vincent 
> wrote:
>
> > And also, in order to group and namespace the Type Alias, i suggest we use
> > `typedef`, like i specify in my last message, it will be like this:
> >
> > File A.php:
> >
> > ```php
> >
> > namespace Package;
> >
> > typedef MyTypes {
> >
> > type Numeric: int|float|null;
> >
> > type Chars: string|null;
> >
> > type Result: bool|null;
> >
> > }
> >
> >
>  I came up with an idea:
>
> In php we don't have inner/nested classes, like in Java.
> But maybe at some point we could have. An inner class would help with
> avoiding some extra files and autoloading, especially when that class would
> be needed as private.
>
> Coming back to types, what if a type would be allowed to be defined on the
> class level?
> It would solve the autoloading problem as it would be loaded together with
> the class.
> And I guess that in real-life, complex types are usually related to some
> code using them, so I expect that identifying a class where the type to be
> placed would not be hard.
> And even if it would be difficult, There can always be a class named Types
> that would have only type definitions.
>
> An example would look like this:
>
> namespace My\App;
> class Types {
> public type Numeric: int|float;
> }
>
> And it could be used with:
>
> use My\App\Types.Numeric;
> function castNumericToFloat(Numeric $number): float {
> return (float)$number;
> }
>
> or
>
> use My\App\Types;
> function castNumericToFloat(Types.Numeric $number): float {
> return (float)$number;
> }
>
> or by using an import alias, of course.
>
> Maybe we can use this construct, along with allowing a type to be defined
> in a normal way, a way that would not permit autoloading.
> However, a way that would better fit code that is procedural and it can be
> loaded in the same functions.php that some projects use.
>
> Allowing inner "types" on classes might be a bit more complex that I can
> ever evaluate.
> But it might open the door for inner classes and there are nice constructs
> that can be built using this.
>
> Regards,
> Alex

My personal opinion is that file-based type aliases would be the best.
It solves an immediate problem while introducing a problem most people
will never have (needing to reuse the type aliases elsewhere). It
allows them to be used in functions and classes, while also making
code more readable but not opaque outside the file. For example, if
there is a type called BigNumber that was an alias of
GMP|int|float|string, outside the file, knowing the actual types in my
IDE is more useful than "BigNumber" and doesn't require me to dig into
the definition or even agree with the other file's definition of
"BigNumber." I just need to know that I need to pass it one of those
types from my own code. However, reading that file's code, I don't
need to know the intimate details of the aliases to make it more
readable.

If we find ourselves constantly writing the same type aliases in a
bunch of files, we only need to wait less than a year to implement
"global" (as in, available once include'ed) in the very next version
of PHP.

Robert Landers
Software Engineer
Utrecht NL

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] Discussion - Anti-null coercion

2023-10-29 Thread Sergii Shymko

On Oct 29, 2023, at 3:23 PM, Robert Landers 
mailto:landers.rob...@gmail.com>> wrote:

Because falsy is different than null/non-existent. The closest
equivalent is "array_key_exists" (instead of empty/isset) but this
proposal isn't just applicable to arrays. I run into this pattern of
"if not null, then do something with the value" pretty often and it is
tedious to type it out.

In terms of falsy values, null coalescing operator ?? is a syntactic sugar for 
isset().
So, ?! operator will be equivalent to !isset() expression in the ternary.

For the reference:
https://www.php.net/manual/en/migration70.new-features.php#migration70.new-features.null-coalesce-op


Re: [PHP-DEV] Discussion - Anti-null coercion

2023-10-29 Thread Robert Landers
On Sun, Oct 29, 2023 at 8:53 PM Sergii Shymko  wrote:
>
>
>
> On Oct 29, 2023, at 1:31 PM, Robert Landers  wrote:
>
> Hello Internals,
>
> We currently have a null coercion operator: ??, but we lack an
> anti-null coercion operator.
>
> For example, if I wanted to operate on a header, if-and-only-if it
> exists, I'd have to write something like this one-liner:
>
> fn() =>
>  ($_SERVER['HTTP_X_MY_HEADER'] ?? null)
>  ? md5($_SERVER['HTTP_X_MY_HEADER'])
>  : null;
>
> Or something like this:
>
> function() {
>  if(!empty($_SERVER['HTTP_X_MY_HEADER']) {
>return md5($_SERVER['HTTP_X_MY_HEADER']);
>  }
>
>  return null;
> }
>
> This is rather tedious when you have to do it, so, I'd like to discuss
> adding a new "anti-null coercion" operator: ?!
>
> This would collapse the previous verbose code into:
>
> fn() =>
>  $_SERVER['HTTP_X_MY_HEADER']
>  ?! md5($_SERVER['HTTP_X_MY_HEADER'];
>
> When it is null, it will stay null, thus the above is the same as:
>
> fn() =>
>  $_SERVER['HTTP_X_MY_HEADER']
>  ?! md5($_SERVER['HTTP_X_MY_HEADER']
>  ?? null;
>
> It would have a lower precedence than ?? so that the above line would
> read from left to right without requiring parenthesis/brackets. The
> operator would only return the right-hand side if the left-hand side
> exists (aka, not null), otherwise, it would return null.
>
> I'm not particularly attached to the ?! syntax (since it does, in
> fact, look very similar to ?:), so perhaps focusing on the merits of
> the idea first, then bikeshedding the syntax later would be a good
> approach?
>
> Thoughts?
>
> Robert Landers
> Software Engineer
> Utrecht NL
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
>
>
> Hi Robert,
>
> Why don’t you combine the two examples and use a regular ternary operator 
> along with isset/empty()?
>
> fn() =>
>   !empty($_SERVER[‘HTTP_X_MY_HEADER’])
>   ? md5($_SERVER[‘HTTP_X_MY_HEADER’])
>   : null;
>
> It’s only ever so slightly longer than the proposed ?! operator, but way more 
> powerful. You explicitly control the evaluation expression along with the 
> default value.
>
> Regards,
> Sergii

Hey Sergii,

> Why don’t you combine the two examples and use a regular ternary operator 
> along with isset/empty()?

Because falsy is different than null/non-existent. The closest
equivalent is "array_key_exists" (instead of empty/isset) but this
proposal isn't just applicable to arrays. I run into this pattern of
"if not null, then do something with the value" pretty often and it is
tedious to type it out.

Robert Landers
Software Engineer
Utrecht NL

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] Discussion - Anti-null coercion

2023-10-29 Thread Fabio Carpi
Following the php logic, maybe !??


From: Sergii Shymko 
Sent: Sunday, October 29, 2023 4:53:12 PM
To: Robert Landers 
Cc: internals 
Subject: Re: [PHP-DEV] Discussion - Anti-null coercion



On Oct 29, 2023, at 1:31 PM, Robert Landers 
mailto:landers.rob...@gmail.com>> wrote:

Hello Internals,

We currently have a null coercion operator: ??, but we lack an
anti-null coercion operator.

For example, if I wanted to operate on a header, if-and-only-if it
exists, I'd have to write something like this one-liner:

fn() =>
 ($_SERVER['HTTP_X_MY_HEADER'] ?? null)
 ? md5($_SERVER['HTTP_X_MY_HEADER'])
 : null;

Or something like this:

function() {
 if(!empty($_SERVER['HTTP_X_MY_HEADER']) {
   return md5($_SERVER['HTTP_X_MY_HEADER']);
 }

 return null;
}

This is rather tedious when you have to do it, so, I'd like to discuss
adding a new "anti-null coercion" operator: ?!

This would collapse the previous verbose code into:

fn() =>
 $_SERVER['HTTP_X_MY_HEADER']
 ?! md5($_SERVER['HTTP_X_MY_HEADER'];

When it is null, it will stay null, thus the above is the same as:

fn() =>
 $_SERVER['HTTP_X_MY_HEADER']
 ?! md5($_SERVER['HTTP_X_MY_HEADER']
 ?? null;

It would have a lower precedence than ?? so that the above line would
read from left to right without requiring parenthesis/brackets. The
operator would only return the right-hand side if the left-hand side
exists (aka, not null), otherwise, it would return null.

I'm not particularly attached to the ?! syntax (since it does, in
fact, look very similar to ?:), so perhaps focusing on the merits of
the idea first, then bikeshedding the syntax later would be a good
approach?

Thoughts?

Robert Landers
Software Engineer
Utrecht NL

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: 
https://na01.safelinks.protection.outlook.com/?url=https%3A%2F%2Fwww.php.net%2Funsub.php=05%7C01%7C%7Cf2f8309c674c4f9137a008dbd8b8b73a%7C84df9e7fe9f640afb435%7C1%7C0%7C638342060099962597%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C3000%7C%7C%7C=Frc%2BghvwIS1q%2B79n4joMssXCfeFIHkf7mziuH28XLW0%3D=0


Hi Robert,

Why don’t you combine the two examples and use a regular ternary operator along 
with isset/empty()?

fn() =>
  !empty($_SERVER[‘HTTP_X_MY_HEADER’])
  ? md5($_SERVER[‘HTTP_X_MY_HEADER’])
  : null;

It’s only ever so slightly longer than the proposed ?! operator, but way more 
powerful. You explicitly control the evaluation expression along with the 
default value.

Regards,
Sergii


Re: [PHP-DEV] Discussion - Anti-null coercion

2023-10-29 Thread Sergii Shymko


On Oct 29, 2023, at 1:31 PM, Robert Landers 
mailto:landers.rob...@gmail.com>> wrote:

Hello Internals,

We currently have a null coercion operator: ??, but we lack an
anti-null coercion operator.

For example, if I wanted to operate on a header, if-and-only-if it
exists, I'd have to write something like this one-liner:

fn() =>
 ($_SERVER['HTTP_X_MY_HEADER'] ?? null)
 ? md5($_SERVER['HTTP_X_MY_HEADER'])
 : null;

Or something like this:

function() {
 if(!empty($_SERVER['HTTP_X_MY_HEADER']) {
   return md5($_SERVER['HTTP_X_MY_HEADER']);
 }

 return null;
}

This is rather tedious when you have to do it, so, I'd like to discuss
adding a new "anti-null coercion" operator: ?!

This would collapse the previous verbose code into:

fn() =>
 $_SERVER['HTTP_X_MY_HEADER']
 ?! md5($_SERVER['HTTP_X_MY_HEADER'];

When it is null, it will stay null, thus the above is the same as:

fn() =>
 $_SERVER['HTTP_X_MY_HEADER']
 ?! md5($_SERVER['HTTP_X_MY_HEADER']
 ?? null;

It would have a lower precedence than ?? so that the above line would
read from left to right without requiring parenthesis/brackets. The
operator would only return the right-hand side if the left-hand side
exists (aka, not null), otherwise, it would return null.

I'm not particularly attached to the ?! syntax (since it does, in
fact, look very similar to ?:), so perhaps focusing on the merits of
the idea first, then bikeshedding the syntax later would be a good
approach?

Thoughts?

Robert Landers
Software Engineer
Utrecht NL

--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php


Hi Robert,

Why don’t you combine the two examples and use a regular ternary operator along 
with isset/empty()?

fn() =>
  !empty($_SERVER[‘HTTP_X_MY_HEADER’])
  ? md5($_SERVER[‘HTTP_X_MY_HEADER’])
  : null;

It’s only ever so slightly longer than the proposed ?! operator, but way more 
powerful. You explicitly control the evaluation expression along with the 
default value.

Regards,
Sergii


[PHP-DEV] Re: Basic Type Alias

2023-10-29 Thread Oladoyinbo Vincent
So, who is going to help with the implementation :)

On Saturday, October 28, 2023, Alexandru Pătrănescu 
wrote:

> Hey,
>
> So actually while reading this:
>
> On Fri, Oct 27, 2023 at 11:42 PM Oladoyinbo Vincent 
> wrote:
>
>> And also, in order to group and namespace the Type Alias, i suggest we use
>> `typedef`, like i specify in my last message, it will be like this:
>>
>> File A.php:
>>
>> ```php
>>
>> namespace Package;
>>
>> typedef MyTypes {
>>
>> type Numeric: int|float|null;
>>
>> type Chars: string|null;
>>
>> type Result: bool|null;
>>
>> }
>>
>>
>  I came up with an idea:
>
> In php we don't have inner/nested classes, like in Java.
> But maybe at some point we could have. An inner class would help with
> avoiding some extra files and autoloading, especially when that class would
> be needed as private.
>
> Coming back to types, what if a type would be allowed to be defined on the
> class level?
> It would solve the autoloading problem as it would be loaded together with
> the class.
> And I guess that in real-life, complex types are usually related to some
> code using them, so I expect that identifying a class where the type to be
> placed would not be hard.
> And even if it would be difficult, There can always be a class named Types
> that would have only type definitions.
>
> An example would look like this:
>
> namespace My\App;
> class Types {
> public type Numeric: int|float;
> }
>
> And it could be used with:
>
> use My\App\Types.Numeric;
> function castNumericToFloat(Numeric $number): float {
> return (float)$number;
> }
>
> or
>
> use My\App\Types;
> function castNumericToFloat(Types.Numeric $number): float {
> return (float)$number;
> }
>
> or by using an import alias, of course.
>
> Maybe we can use this construct, along with allowing a type to be defined
> in a normal way, a way that would not permit autoloading.
> However, a way that would better fit code that is procedural and it can be
> loaded in the same functions.php that some projects use.
>
> Allowing inner "types" on classes might be a bit more complex that I can
> ever evaluate.
> But it might open the door for inner classes and there are nice constructs
> that can be built using this.
>
> Regards,
> Alex
>


Re: [PHP-DEV] New DateTime[Immutable]::createFromTimestamp

2023-10-29 Thread Marc



On 29.10.23 19:41, Marc wrote:

Hi Saki,

On 28.10.23 18:32, Saki Takamachi wrote:

Hi Marc,

On a 64bit system it's obvious to have higher precision if you 
handle the integer and fractions part separately (as timelib does) 
but this doesn't help if you already have a floating point number at 
hand. Also JS uses a double float for timestamps in milliseconds 
which is the most used lang together with PHP and there is tons of 
code out there who does a simple */ 1000 to pass a date-time to/from 
JS, which I wouldn't necessary decline.
I think there is no problem if it is up to milliseconds. This becomes 
a problem when it includes up to microseconds.


Another problem is that there are "millisecond" and "microsecond" 
timestamp formats that do not include dots, how should they be 
handled? In reality, such a use case is unlikely, but it is virtually 
impossible to tell the difference between the two:


timestamp: 1698510347
=> second: 2023-10-28 16:25:47(UTC)
=> millisecond: 1970-01-20 15:48:30.347(UTC)


I'm not sure I fully understand what you mean.

Obviously if you have a string to be parsed you need to use the 
existing `createFromFormat`.



One think that could be done is adding an optional second argument for
allowing the microseconds part but again forcing PHP users to extract
seconds and microseconds from a float isn't user friendly so I would
still allow a float in the first place which than opens the question
what to do if both arguments have fractions. Additionally this would
break Carbons `createFromTimestamp($timestamp, $tz = null)`.


Instead it would probably be better to add a `[get|set]Microseconds`
method as well instead. I'm open for adding another PR for this.


Just opened another PR for adding `[get|set]Microseconds` to support 
handling seconds + microseconds as separate integers.

Missed the link: https://github.com/php/php-src/pull/12557



Regards.

Saki



Best,
Marc



--
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] New DateTime[Immutable]::createFromTimestamp

2023-10-29 Thread Marc

Hi Saki,

On 28.10.23 18:32, Saki Takamachi wrote:

Hi Marc,


On a 64bit system it's obvious to have higher precision if you handle the 
integer and fractions part separately (as timelib does) but this doesn't help 
if you already have a floating point number at hand. Also JS uses a double 
float for timestamps in milliseconds which is the most used lang together with 
PHP and there is tons of code out there who does a simple */ 1000 to pass a 
date-time to/from JS, which I wouldn't necessary decline.

I think there is no problem if it is up to milliseconds. This becomes a problem 
when it includes up to microseconds.

Another problem is that there are "millisecond" and "microsecond" timestamp 
formats that do not include dots, how should they be handled? In reality, such a use case is 
unlikely, but it is virtually impossible to tell the difference between the two:

timestamp: 1698510347
=> second: 2023-10-28 16:25:47(UTC)
=> millisecond: 1970-01-20 15:48:30.347(UTC)


I'm not sure I fully understand what you mean.

Obviously if you have a string to be parsed you need to use the existing 
`createFromFormat`.



One think that could be done is adding an optional second argument for
allowing the microseconds part but again forcing PHP users to extract
seconds and microseconds from a float isn't user friendly so I would
still allow a float in the first place which than opens the question
what to do if both arguments have fractions. Additionally this would
break Carbons `createFromTimestamp($timestamp, $tz = null)`.


Instead it would probably be better to add a `[get|set]Microseconds`
method as well instead. I'm open for adding another PR for this.


Just opened another PR for adding `[get|set]Microseconds` to support 
handling seconds + microseconds as separate integers.



Regards.

Saki



Best,
Marc


[PHP-DEV] Discussion - Anti-null coercion

2023-10-29 Thread Robert Landers
Hello Internals,

We currently have a null coercion operator: ??, but we lack an
anti-null coercion operator.

For example, if I wanted to operate on a header, if-and-only-if it
exists, I'd have to write something like this one-liner:

fn() =>
  ($_SERVER['HTTP_X_MY_HEADER'] ?? null)
  ? md5($_SERVER['HTTP_X_MY_HEADER'])
  : null;

Or something like this:

function() {
  if(!empty($_SERVER['HTTP_X_MY_HEADER']) {
return md5($_SERVER['HTTP_X_MY_HEADER']);
  }

  return null;
}

This is rather tedious when you have to do it, so, I'd like to discuss
adding a new "anti-null coercion" operator: ?!

This would collapse the previous verbose code into:

fn() =>
  $_SERVER['HTTP_X_MY_HEADER']
  ?! md5($_SERVER['HTTP_X_MY_HEADER'];

When it is null, it will stay null, thus the above is the same as:

fn() =>
  $_SERVER['HTTP_X_MY_HEADER']
  ?! md5($_SERVER['HTTP_X_MY_HEADER']
  ?? null;

It would have a lower precedence than ?? so that the above line would
read from left to right without requiring parenthesis/brackets. The
operator would only return the right-hand side if the left-hand side
exists (aka, not null), otherwise, it would return null.

I'm not particularly attached to the ?! syntax (since it does, in
fact, look very similar to ?:), so perhaps focusing on the merits of
the idea first, then bikeshedding the syntax later would be a good
approach?

Thoughts?

Robert Landers
Software Engineer
Utrecht NL

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



Re: [PHP-DEV] Passing null to parameter

2023-10-29 Thread Craig Francis
On 29 Oct 2023, at 11:14, Kamil Tekiela  wrote:
> A code like this already throws a fatal error.
> 
> function enc(string $a){}
> enc(null);
> 
> The only thing remaining to be fixed in PHP 9 is to make this error 
> consistent on all function invocations.



Or, be consistent with all of the other type coercions?


```
function user_function(string $s, int $i, float $f, bool $b) {
  var_dump($s, $i, $f, $b);
}
 
user_function('1', '1', '1', '1');
  // string(1) "1" / int(1) / float(1) / bool(true)
 
user_function(2, 2, 2, 2);
  // string(1) "2" / int(2) / float(2) / bool(true)
 
user_function(3.3, 3.3, 3.3, 3.3);
  // string(3) "3.3" / int(3), lost precision / float(3.3) / bool(true)
 
user_function(false, false, false, false);
  // string(0) "" / int(0) / float(0) / bool(false)
```


The documentation does clearly say how NULL should be coerced:

https://www.php.net/manual/en/language.types.string.php
"null is always converted to an empty string."

https://www.php.net/manual/en/language.types.integer.php
"null is always converted to zero (0)."

https://www.php.net/manual/en/language.types.float.php
"For values of other types, the conversion is performed by converting the value 
to int first and then to float"

https://www.php.net/manual/en/language.types.boolean.php
"When converting to bool, the following values are considered false [...] the 
special type NULL"


Maybe documentation should be amended to say "except when being passed to a 
function"?

Or, should we have fatal errors with the following as well:

```
$nullable = NULL;

print($nullable);

echo $nullable;

printf('%s', $nullable);

var_dump('A' . $nullable);

var_dump(3 + $nullable);

var_dump($nullable / 6);

var_dump('' == $nullable);
```



> Without it, you would never know that you have a logical error in your code.


But it's not an error?

Craig



Re: [PHP-DEV] Passing null to parameter

2023-10-29 Thread Kamil Tekiela
A code like this already throws a fatal error.

function enc(string $a){}
enc(null);

The only thing remaining to be fixed in PHP 9 is to make this error
consistent on all function invocations.

> I didn't realise the payment gateway doesn't always provide the order
reference

Well, there you go. This deprecation message actually informed you of
something. Without it, you would never know that you have a logical
error in your code. It works as intended.

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php



[PHP-DEV] Passing null to parameter

2023-10-29 Thread Craig Francis
Hi Internals,

I'm getting really annoyed at the "Passing null to parameter" problem, and
it happens with new code as well.

I know you have distain for websites that don't use strict types, or static
analysis at the strictest level, but yesterday I was working on a 15 year
old website, it still works well, it uses PHP as a simple scripting
language... because the payment gateway returns a user to the websites
thank-you page with a POST request, and customers leave this page open,
browsers complain (asking to re-submit data), so I just needed to change it
to a GET request, with the order reference in the URL, so I stupidly added
this:

```
if (($_SERVER['REQUEST_METHOD'] ?? '') == 'POST') {
  redirect('/thank-you/?ref=' . urlencode($ref));
}
```

I didn't realise the payment gateway doesn't always provide the order
reference, so the function to get the $ref from the POST request returns
NULL... at the moment that's just an annoying deprecation, but does it
really need to become a fatal error in PHP 9?

Should I be using Rector to update this to `urlencode((string) $ref)`?

Keep in mind, we can still compare NULL to an empty string, concatenate
NULL onto a string, add NULL to an integer/float, and echo/print/sprintf
NULL, we can even use NULL for an array key (as in, it get coerced to an
empty string)... and type coercion happens in other contexts as well, e.g.
passing the string "5" to an integer argument... but NULL will be special,
and cause a fatal type error? really?

Craig