Re: [PHP-DEV] Why are serialized strings wrapped in double quotes? (s::"")

2024-02-07 Thread Michał Marcin Brzuchalski
Hi Sandy,

wt., 6 lut 2024 o 21:19 Sanford Whiteman 
napisał(a):

> Howdy all, haven't posted in ages but good to see the list going strong.
>
> I'd like a little background on something we've long accepted: why
> does the serialization format need double quotes around a string, even
> though the byte length is explicit?
>
> Example:
>
>   s:5:"hello";
>
> All else being equal I would think we could have just
>
>   s:5:hello;
>
> and skip forward 5 bytes. Instead we need to be aware of the leading
> and trailing " in our state machine but I'm not sure what the
> advantage is.
>

You inspired me to play with serialization format to spot even more
unnecessary chars https://3v4l.org/DLh1U
>From my PoV there are more candidates to reduce and still keep the safety,
for eg:
removing leading ':' before array/object and trailing ';' inside brackets,
you reduce by 2 bytes

a:4:{i:0;i:123;i:1;b:1;i:2;d:1.1;i:3;s:3:"baz";}

Could be simply

a:4{i:0;i:123;i:1;b:1;i:2;d:1.1;i:3;s:3:baz}

This example saves 4 bytes: double-quotes, one ; and :

If you go further all types that require size/length also don't need extra
double-colon meaning:
a:4 could become a4
s:3 could become s3

The same could apply to O: and E:

O3:Foo:5{s4:date;O17:DateTimeImmutable:3{s4:date;s26:2024-02-08
08:41:10.009742;s13:timezone_type;i:3;s8:timezone;s16:Europe/Amsterdam}s6:*foo;s11:Foo
bar
baz;s8:Foobar;i:123456789;s3:tbl;a4{i:0;i:123;i:1;b:1;i:2;d:1.1;i:3;s3:baz}s8:*color;E12:Color:Yellow}

This is still readable by humans and keep the size/length in all places
where needed.
My attached example is poor but shows up to ~20% size reduction.

Interestingly when an array is serialized as object property it is not
followed by ; in field list https://3v4l.org/4p6ve

O:3:"Foo":2:{s:3:"foo";a:3:{i:0;i:1;i:1;i:2;i:2;i:3;}s:3:"bar";s:3:"baz";}

Missing ; between }s was a surprise to me.

Best regards,
Michał Marcin Brzuchalski


Re: [PHP-DEV] Feature request: https://github.com/php/php-src/issues/13301

2024-02-07 Thread Григорий Senior PHP / Разработчик Web
JIT I've had this solved, not only the application, but a way to.

Am sharing my experience without labels "bad", "cood", "truth" or
"correct", like you did.

Your arguments are based on your principles and I don't see in your words
any point to discuss, so - use pm or share here secret of error-free code,
if you have ideas how to solve "my" application if "you know what is the
correct design".

I think the people who use labels usually never share their experience.


Re: [PHP-DEV] Feature request: https://github.com/php/php-src/issues/13301

2024-02-07 Thread Alexander Pravdin
On Thu, Feb 8, 2024 at 2:29 AM Григорий Senior PHP / Разработчик Web
<6562...@gmail.com> wrote:

> I still don't understand why the problem is signature and moving a simple
> throw statement to return type, and then rewriting the catch statement to
> oneline-r.

Sorry for answering not directly to the citation. But from my personal
opinion, a static analyzer like PHPStan with the highest level of
assertion will show you the vast majority of issues in the code,
potential errors, warnings, etc. Just feed your code to it and fix it.
Why do you need to collect errors and warnings on every API call? Edge
cases are called edge because happen rarely and you can react to them
successfully with proper error monitoring. This looks like a bad
design of the app and of the monitoring tools that you propose to
"fix" with bandaids in the language.

>  This is where the so-called SOLID came from, which forces
> everything to be broken down into molecules instead of first closing the
> problem and then deciding whether to break it into parts or leave it that
> way.

This is called not SOLID, this is called a good application
architecture. When an application is designed properly, the delivery
speed is always slow in the beginning. But later it allows much speedy
deliveries because developers don't need to refactor large parts of it
on every new feature. And don't need to rely on bandaids in the
language to save their butt from burning because of working with
shitty architecture.

It is always easy to write down some piece of shit just to close
tickets and fulfill initial requirements and don't care. But I still
don't understand why you keep asking the PHP language community to do
your job and fix your application instead of you?


--
Best, Alexander.

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



Re: [PHP-DEV] Why are serialized strings wrapped in double quotes? (s::"")

2024-02-07 Thread Sanford Whiteman
Nice work, Jim.

>I enjoy spelunking in the history of the project, so I did some digging. It
>looks to me like Kris didn't quite get the history correct. Boris did propose
>a form of serialization first, but it looks like what became serialize() and
>unserialize() came into the project another way.
>
>https://marc.info/?l=php-general=90222513234434=2
>
>The serialize() and unserialize() functions were first added in PHP 3.0.5
>with that same encoding for strings that you're asking about. Here is the
>original proposal for adding the functions from Jani Lehtimäki:
>
>https://news-web.php.net/php.dev/1444
>
>The were originally conceived as var_save() and var_load() and operated on
>files, but you can see the file format uses the same string encoding, although 
>it used single quotes.
>
>It was committed to CVS by Stig here, but unfortunately the emails to the list 
>didn't include newly-added files.
>
>https://news-web.php.net/php.dev/1540

Huh. So the quotes may have just stuck around from eval()-related approaches
without being officially discussed. In the grand scheme even if you're wasting 2
bytes for every string that could be a tiny % on average.

The format's fascinating because it unmistakably *works*, and binary
igbinary/msgpack aside, it's a pretty good byte-stream encoding. If you take
Sergey's results it's way faster than JSON, at least when it's PHP doing the
unserialization:
https://grechin.org/2021/04/06/php-json-encode-vs-serialize-performance-comparison.html

— S.

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



Re: [PHP-DEV] [RFC][Vote] Promote the PHP Foundation

2024-02-07 Thread Jim Winstead
On Fri, Feb 2, 2024, at 12:57 AM, Jorg Sowa wrote:
> Hello Jim,
> shoudl this RFC be placed into the Policies repository as it was accepted?
>
> https://github.com/php/policies

I'm not sure that it's necessary, but if it fits in there somehow I have no 
problem with it. I didn't see this as an adoption of a policy, it was just a 
way of running a change that was seen as potentially controversial through a 
process that put it in front of as many as people as feasible.

Thanks.

Jim

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



Re: [PHP-DEV] Why are serialized strings wrapped in double quotes? (s::"")

2024-02-07 Thread Jim Winstead
On Tue, Feb 6, 2024, at 12:19 PM, Sanford Whiteman wrote:
> Howdy all, haven't posted in ages but good to see the list going strong.
>
> I'd like a little background on something we've long accepted: why
> does the serialization format need double quotes around a string, even
> though the byte length is explicit?

I enjoy spelunking in the history of the project, so I did some digging. It 
looks to me like Kris didn't quite get the history correct. Boris did propose a 
form of serialization first, but it looks like what became serialize() and 
unserialize() came into the project another way.

https://marc.info/?l=php-general=90222513234434=2

The serialize() and unserialize() functions were first added in PHP 3.0.5 with 
that same encoding for strings that you're asking about. Here is the original 
proposal for adding the functions from Jani Lehtimäki:

https://news-web.php.net/php.dev/1444

The were originally conceived as var_save() and var_load() and operated on 
files, but you can see the file format uses the same string encoding, although 
it used single quotes.

It was committed to CVS by Stig here, but unfortunately the emails to the list 
didn't include newly-added files.

https://news-web.php.net/php.dev/1540

I'm not sure if the old CVS history is preserved somewhere, but based on what 
appeared in 3.0.5, that format probably goes back to the beginning and it 
doesn't look like there was any on-list discussion about it.

Jim

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



Re: [PHP-DEV] Feature request: https://github.com/php/php-src/issues/13301

2024-02-07 Thread Григорий Senior PHP / Разработчик Web
I still don't understand why the problem is signature and moving a simple
throw statement to return type, and then rewriting the catch statement to
oneline-r.

I am completely satisfied with the php way of working with method
signatures except non-critical cases:
- still no `undefined` type, so some functions have limited functionality
with func_num_args() inside
- no languages still implement emptiness check on argument types. empty
string should always be additionally asserted, like positive-negative
numbers, and nan/inf with float stuff (nan/inf is too rarely case)
- I'd say generics support but it is fully covered with phpdoc. use
argument Generic, mark it as class-string and @template and it works well

Try/catch statements don't scare me.

I feel the trouble in missing try/catch statements and requirements to
check all method call places once you throw a non-critical error just
because another way, sorry, necessary way, is too hard for fast
implementation. That trouble arrives only when you move from single-task
script to multi-task script. The nearest example is SQL, which always works
with rows and never returns one value, response is always "list of rows".

So the primary method of error handling should be focused on batch
processing, but `throw` keyword is very handy for filters, assertions,
validators and low level static functions.

If you finish your code fully covered with exceptions - once you try to run
several times the same with try/catch over method calls - the original
action code could have been better by catching some exceptions on its own.
However, it is closed to you and now if you want to break it into two
parts, you will have to rewrite it completely, because it is completely
closed to you and the slightest exception that was not caught in itself
(and not in you) will break it entirely, and will not disable part of it.

The exception was invented in order to shift the closure of the problem to
the next level of developers. However, it is the exception that prevents
these developers from changing the source logic of the code that throws it
and continuing to perform the action intended in the source code - the
exception simply breaks the entire branch (following `encapsulation`). This
means it should break only the most primitive functions that can be
replaced quickly. This is where the so-called SOLID came from, which forces
everything to be broken down into molecules instead of first closing the
problem and then deciding whether to break it into parts or leave it that
way.


Re: [PHP-DEV] Why are serialized strings wrapped in double quotes? (s::"")

2024-02-07 Thread Sanford Whiteman
> I don't have the historical context, but I'm assuming that's it. PHPs
> serialization format is not efficient, and I don't think that was ever
> the primary focus.

Thanks Ilija. That'll have to suffice unless someone remembers a specific
decision (searching all the old Internals posts nothing came up). Most of my
readers are pretty junior but I hate to say something that conflicts with
their intuition.

— S.

On Wed, Feb 7, 2024 at 7:28 AM Ilija Tovilo  wrote:
>
> Hi Sandy
>
> On Tue, Feb 6, 2024 at 9:19 PM Sanford Whiteman  
> wrote:
> >
> > I'd like a little background on something we've long accepted: why
> > does the serialization format need double quotes around a string, even
> > though the byte length is explicit?
> >
> > Example:
> >
> >   s:5:"hello";
> >
> > All else being equal I would think we could have just
> >
> >   s:5:hello;
> >
> > Was this just to make strings look more 'stringy', even though the
> > format isn't meant to be human-readable?
>
> I don't have the historical context, but I'm assuming that's it. PHPs
> serialization format is not efficient, and I don't think that was ever
> the primary focus. If you need something more efficient, you can try
> https://github.com/igbinary/igbinary which is aimed to be a drop-in
> replacement.
>
> Ilija
>
> --
> PHP Internals - PHP Runtime Development Mailing List
> To unsubscribe, visit: https://www.php.net/unsub.php
>

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



Re: [PHP-DEV] Feature request: https://github.com/php/php-src/issues/13301

2024-02-07 Thread Larry Garfield
On Wed, Feb 7, 2024, at 12:55 AM, Alex Wells wrote:
> On Tue, Feb 6, 2024 at 7:14 PM Larry Garfield 
> wrote:
>
>> These two samples *are logically identical*, and even have mostly the same
>> performance characteristics, and both expose useful data to static
>> analyzers.  They're just spelled differently.  The advantage of the second
>> is that it could be implemented without generics.  (ADTs would be an
>> optional nice-to-have.)  And if the caller doesn't handle DivByZero, it
>> would try to pass it up to its caller, but being checked it would require
>> the caller to also declare that it can raise DivByZero.
>>
>
> Let's assume that the developer knows the divisor isn't 0 - through an
> assertion or an `if` clause above the call to `divide(5, $divisor)`. In
> this case, DivByZero error cannot ever be thrown (or risen), but the
> developer would still have to either handle the error (which will never
> happen) or declare it as raisable, which in turn may require also marking
> 10+ function/method calls as "raises DivByZero". Both options aren't great.
>
> And even if there was no assertion about the divisor, maybe the developer's
> intent is exactly to ignore that case as an "implicit assertion" - meaning
> instead of explicitly asserting the divisor value themselves (through
> `assert($divisor !== 0)`), they rely on `divide(5, $divisor)` doing that
> implicitly for them. If the `assert()` fails, then nobody is expected to
> really handle that assertion error; it usually bubbles up to the global
> exception handler which takes care of it. If the `divide()` fails on the
> other hand, checked exceptions would require all the callers to actually
> "check" it by catching or declaring the caller function as `raises
> DivByZero`, but this doesn't bring any benefit to the developer in this
> case.
>
> So I assume this is why Java developers hate checked exceptions and why
> Kotlin doesn't have them. I'm not aware of other implementations of checked
> exceptions; there may be other, better versions of them. If you have any in
> mind that overcome the issues above, I'd be interested to look into them :)

Re assertions: The problem with assertions is they can be disabled.  They're 
really *only* useful as an extra "extended type check", and then only in dev.  
That makes them unreliable, so using them for flow control is right out.  And 
in practice they just turn into exceptions anyway (or Throwables at least), so 
there's really no benefit over just using a Throwable if you're going to insist 
they aren't disabled for the code to work.

The Joe Duffy article I linked above describes the issues with Java's exception 
design.  Mainly, it's only mostly-checked.  It forces you to declare your 
throwables... but certain types of throwables don't need to be declared, which 
means as a consumer of a function, you have no guarantee that a function that 
has no declared throws will actually never throw.  So you get all the pain, 
none of the gain.  (This is admittedly a challenge for introducing them to PHP 
as well, which is why I am proposing a separate syntax from exceptions since 
they would serve a different purpose.)

As discussed in the article, Midori (the experimental language for which Duffy 
was tech lead) had checked exceptions that worked essentially as I have 
proposed here.  What made them work is

* They were very lightweight.
* They were firmly and strictly checked, without any "holes" in the design like 
Java.
* They were used locally, as an unwrapped Either monad, rather than for 
up-the-stack communication.
* Midori had a much more robust type checker than Java, so more errors could be 
moved to the type system and eliminated entirely.
* The built-in type hierarchy was more sensible than Java's.
* Midori has guards, which eliminate 99% of cases.  It's essentially promoting 
assertion-esque type checking into the function signature.  That is, DivByZero 
wouldn't even be an exception, it would be a runtime enforced type error.  I'd 
love to have these, too, but that's not the topic right now. :-)

Guards would look something like this (using Midori-inspired syntax):

function divide(float $a, float $b): float require $b !== 0 ensures return != 
INF { 
// ...
}

(In Midori, those could either be materialized into code or compiled away if 
the compiler could guarantee they held true.  In PHP I don't think we could 
compile them away so they'd have to be materialized, but it would make them 
more apparent to static analyzers as well as better communicate intent to other 
developers.)

The article goes into much more detail, and I really do encourage reading it.

To your specific question about prior knowledge (eg, non-zero), there's a 
couple of ways, conceptually, to address that.

1. A more robust type system can handle things like non-zero-int or 
unsigned-int as a type.  (I believe Midori has this, but honestly it's unlikely 
for PHP.)
2. Guard clauses.
3. Better syntax making handling "no op 

Re: [PHP-DEV] Feature request: https://github.com/php/php-src/issues/13301

2024-02-07 Thread Григорий Senior PHP / Разработчик Web
As I mentioned above - javascript pipelines (named `Promise` and
`Thenable`) are great examples when exceptions are a bad choice. Btw, not
"bad", but "choice to stop one step of the chain only".

If any step of chain/foreach throws an exception - it will break all code.
Should break one step. That's why you throw the immediate catch. And
continue to check via if-checking once the result of the pipeline is
received.

Catching is a good solution for the application core. If some exception
pops up at the entrypoint - you could transform the exception to the
output. All other cases should be covered without exceptions. If you use
exceptions on any occurred error as "truth way" you will meet risk and also
timeloss on any misformatted batches/user-inputs.

ср, 7 февр. 2024 г. в 18:06, Григорий Senior PHP / Разработчик Web <
6562...@gmail.com>:

> Analyzing the problem on a single level operation is incorrect. New code
> and simple operations are fully covered with exception/try/catch flow.
>
> The main point i tried to attract your attention is that if you working in
> batches/queues/pipelines you still need errors collection, and if you made
> error flow with exceptions - you have to extract validations to separate
> classes/dto-s, made return types as objects, try/catching as fast as
> possible, and then you will still met errors from remote systems, network
> errors, and invalid response parsing that need to be logged as much close
> to task registration place.
>
> So correct analysis - providing an example with at least foreaches/yields
> instead of simply calling native functions. In small functions IF
> statements are overkill, and even try-catch could be skipped, because the
> whole script will fall and that's correct behavior.
>
> Case is in that the script should continue working while working with
> chaining/nesting, and should be able to easily refactor any step to skip
> one or more bulk-data rows of each step on any nesting level.
>


-- 
+375 (29) 676-48-68 <+375296764868> / Mobile - предпочитаемый способ связи
https://t.me/gzhegow / https://t.me/%2B375296764868 / Telegram
6562...@gmail.com


Re: [PHP-DEV] Feature request: https://github.com/php/php-src/issues/13301

2024-02-07 Thread Григорий Senior PHP / Разработчик Web
Analyzing the problem on a single level operation is incorrect. New code
and simple operations are fully covered with exception/try/catch flow.

The main point i tried to attract your attention is that if you working in
batches/queues/pipelines you still need errors collection, and if you made
error flow with exceptions - you have to extract validations to separate
classes/dto-s, made return types as objects, try/catching as fast as
possible, and then you will still met errors from remote systems, network
errors, and invalid response parsing that need to be logged as much close
to task registration place.

So correct analysis - providing an example with at least foreaches/yields
instead of simply calling native functions. In small functions IF
statements are overkill, and even try-catch could be skipped, because the
whole script will fall and that's correct behavior.

Case is in that the script should continue working while working with
chaining/nesting, and should be able to easily refactor any step to skip
one or more bulk-data rows of each step on any nesting level.


Re: [PHP-DEV] Feature request: https://github.com/php/php-src/issues/13301

2024-02-07 Thread Larry Garfield
On Wed, Feb 7, 2024, at 10:21 AM, Robert Landers wrote:


>> I think there's a subtle but important difference here between what you're 
>> describing as the problem and what you implied the solution was (which I 
>> then ran with).
>>
>> What you're talking about is trying to change the error handling model of 
>> existing code without changing function signatures.  There are only two 
>> possible ways to do that, both of them bad: Unchecked exceptions and globals.
>>
>> What I described, based on the syntax you offered, is checked exceptions, 
>> which necessarily means changing the function signature.  Error handling is 
>> part of the contract of a function.  If its error handling changes, it 
>> *should* have a signature change to indicate that.  (That unchecked 
>> exceptions do not do that is the problem with unchecked exceptions.)  So if 
>> "no changes to existing code" is the goal, checked exceptions as I describe 
>> them are not the answer you are looking for.
>>
>> It seems from your latest message that you're describing more a generalized 
>> version of `json_last_error()` and similar functions.  The problem there is 
>> that such an API design is generally considered very poor practice outside 
>> of C, because it's all necessarily based on globals and "hope you remembered 
>> to check the thing that no one told you to check and is not even slightly 
>> obvious to check".  That is not something I would want better support for in 
>> the language at all.  There's probably cleaner ways to emulate it in 
>> user-space, but that is for a particular application to sort out.  There's 
>> definitely cleaner monadic solutions (which I've written before and are 
>> quite neat) using a writer/logger monad, but that again doesn't meet your 
>> "don't change existing code" requirement.  I don't think anything the 
>> language can do will meet that requirement and be a good design.
>>
>> --Larry Garfield

>
> Oh wow, this conversation got really interesting while I was asleep :D
>
> I think this could actually be interesting in a
> semi-backwards-compatible way, by just adding some syntax sugar:
>
> function getResult(): ?Result, ?ResultError {
>   if($error) return null, $error;
> }
>
> instead of, but this would still work when destructuring:
>
> function getResult(): array {
>   if($error) return [null, $error);
> }
>
> This would still work (the "backwards compatible" part):
>
> [$result, $error] = getResult();
>
> or this:
>
> $result, $error = getResult();
>
> Essentially, return types with a comma are just a "strongly typed
> array" and a comma on the left-hand side of assignment is just a
> destructure.

What you're describing here is basically porting Go multi-returns to PHP.  That 
is also an option, though I would probably not be in favor of it.  For one, it 
doesn't really offer much beyond the union returns we already have.  For two, 
it seems like it would necessitate nullable returns for both parts, which is a 
hard-no from me on type safety.  It's going to confuse static analyzers badly.

For three, the necessary idioms around Go's error handling are legendarily the 
butt of jokes.

a, err := step_one()
if (err) {
  return err
}

b, err := step_two(a)
if (err) {
  return err
}

c, err := step_two(a, b)
if (err) {
  return err
}

And so on.  It's checked exceptions without the ergonomics. :-)

--Larry Garfield

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



Re: [PHP-DEV] Why are serialized strings wrapped in double quotes? (s::"")

2024-02-07 Thread Ilija Tovilo
Hi Sandy

On Tue, Feb 6, 2024 at 9:19 PM Sanford Whiteman  wrote:
>
> I'd like a little background on something we've long accepted: why
> does the serialization format need double quotes around a string, even
> though the byte length is explicit?
>
> Example:
>
>   s:5:"hello";
>
> All else being equal I would think we could have just
>
>   s:5:hello;
>
> Was this just to make strings look more 'stringy', even though the
> format isn't meant to be human-readable?

I don't have the historical context, but I'm assuming that's it. PHPs
serialization format is not efficient, and I don't think that was ever
the primary focus. If you need something more efficient, you can try
https://github.com/igbinary/igbinary which is aimed to be a drop-in
replacement.

Ilija

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



Re: [PHP-DEV] Feature request: https://github.com/php/php-src/issues/13301

2024-02-07 Thread Robert Landers
On Wed, Feb 7, 2024 at 11:27 AM Григорий Senior PHP / Разработчик Web
<6562...@gmail.com> wrote:
>
> Yes, that was the second build of the error bag I presented in the github 
> ticket.
> First one was a Trait that added an error bag as property in class and 
> returned an array with two results.
>
> The trouble was you have to refactor all places you used your function 
> doesn't matter, want you or not.
>
> And the last build just collects errors to the global stack of error bags 
> allowing you to stay untouched by the existing code.
>
> Of course, if code should start to return null/null-object as result - you 
> have to implement that (refactoring the places where null is inapplicable), 
> but error collection itself won't change existing code then, it works like an 
> observer pattern now.
>
> ср, 7 февр. 2024 г. в 13:21, Robert Landers :
>>
>> On Tue, Feb 6, 2024 at 9:22 PM Larry Garfield  wrote:
>> >
>> > On Tue, Feb 6, 2024, at 7:56 PM, Григорий Senior PHP / Разработчик Web 
>> > wrote:
>> > > Thanks Larry, I will read both articles next weekend.
>> > >
>> > > Am not even talking about changing `throw` to `raise`.
>> > >
>> > > Am talking only about:
>> > > - production ready code
>> > > - that should be able to refactor with error collectors (that was not
>> > > implemented years ago)
>> > > - without touching return types
>> > > - without touching input arguments of existing code
>> > > - without possible code fall after throw exception: you have to try/catch
>> > > all places you use that function (sometimes you predict possible error, 
>> > > and
>> > > yes, write return class/enum to extend/refactor it later)
>> > > (and yes, if old code did not support returning null/null-object before -
>> > > you have to refactor return types then)
>> > >
>> > > While working with queues you have a list of tasks
>> > > - then you reduce it to smaller with reducer (unique/filter/merge)
>> > > - then do some queries
>> > > - then walk initial data using reduced results: copying reports to save
>> > > errors/warnings to each task separately
>> > >
>> > > It cannot be solved with exceptions. In addition, large arrays throw
>> > > exceptions that cause timeloss. It's definitely not a tool for.
>> > > Also your method could return many errors (today - only one
>> > > error/exception), and you need to write a second method, then call the
>> > > second method, then debug the second method.
>> > >
>> > > So what's in rest? Arrays collection of warnings and errors. Changing
>> > > return types or passing second-return by reference.
>> > >
>> > > [ Enum case ~ DTO output ] covers newly written code. Old code is
>> > > uncovered. You have to rewrite a full tree, that's why some trick is
>> > > necessary.
>> > >
>> > > I did it my way with an error bag stack. I enable it inside the function 
>> > > or
>> > > in place I call the function. I want to share this experience, and 
>> > > imagined
>> > > it would be better for all users. It could be done without 2 classes, 10
>> > > functions and work with push/pop/current (closer to ob_start/ob_get_clean
>> > > story).
>> > > I guess it could be implemented if `raise` world will put any data to the
>> > > current error bag in the stack. Exactly if the current error bag is 
>> > > present
>> > > (declared manually like you can declare() strict types or ticks for some
>> > > scope).
>> > >
>> > > I agree that there's more mandatory problems to solve that I didn't even
>> > > know about.
>> > > I tried to talk about error handling with a few developers, all of them
>> > > recommend:
>> > > 1. Use exceptions, don't make anything fresh
>> > > 2. Do validation at the script start to reduce the count of errors later
>> > >
>> > > I've just encountered cases where bugs come from within - once you
>> > > integrate a really bad external system with its own checks, which are
>> > > described in hundreds of documents, I'm sure you'll encounter new bugs 
>> > > once
>> > > the "working" code is released to production. And then you will need to
>> > > quickly and easily reorganize it.
>> > >
>> > > And you can't.
>> > > And you will be sad.
>> > > And, "PHP moves differently" is a completely wrong principle, I believe 
>> > > in
>> > > "watching for".
>> > I think there's a subtle but important difference here between what you're 
>> > describing as the problem and what you implied the solution was (which I 
>> > then ran with).
>> >
>> > What you're talking about is trying to change the error handling model of 
>> > existing code without changing function signatures.  There are only two 
>> > possible ways to do that, both of them bad: Unchecked exceptions and 
>> > globals.
>> >
>> > What I described, based on the syntax you offered, is checked exceptions, 
>> > which necessarily means changing the function signature.  Error handling 
>> > is part of the contract of a function.  If its error handling changes, it 
>> > *should* have a signature change to indicate that.  (That unchecked 

Re: [PHP-DEV] Feature request: https://github.com/php/php-src/issues/13301

2024-02-07 Thread Григорий Senior PHP / Разработчик Web
Yes, that was the second build of the error bag I presented in the github
ticket.
First one was a Trait that added an error bag as property in class and
returned an array with two results.

The trouble was you have to refactor all places you used your function
doesn't matter, want you or not.

And the last build just collects errors to the global stack of error bags
allowing you to stay untouched by the existing code.

Of course, if code should start to return null/null-object as result - you
have to implement that (refactoring the places where null is inapplicable),
but error collection itself won't change existing code then, it works like
an observer pattern now.

ср, 7 февр. 2024 г. в 13:21, Robert Landers :

> On Tue, Feb 6, 2024 at 9:22 PM Larry Garfield 
> wrote:
> >
> > On Tue, Feb 6, 2024, at 7:56 PM, Григорий Senior PHP / Разработчик Web
> wrote:
> > > Thanks Larry, I will read both articles next weekend.
> > >
> > > Am not even talking about changing `throw` to `raise`.
> > >
> > > Am talking only about:
> > > - production ready code
> > > - that should be able to refactor with error collectors (that was not
> > > implemented years ago)
> > > - without touching return types
> > > - without touching input arguments of existing code
> > > - without possible code fall after throw exception: you have to
> try/catch
> > > all places you use that function (sometimes you predict possible
> error, and
> > > yes, write return class/enum to extend/refactor it later)
> > > (and yes, if old code did not support returning null/null-object
> before -
> > > you have to refactor return types then)
> > >
> > > While working with queues you have a list of tasks
> > > - then you reduce it to smaller with reducer (unique/filter/merge)
> > > - then do some queries
> > > - then walk initial data using reduced results: copying reports to save
> > > errors/warnings to each task separately
> > >
> > > It cannot be solved with exceptions. In addition, large arrays throw
> > > exceptions that cause timeloss. It's definitely not a tool for.
> > > Also your method could return many errors (today - only one
> > > error/exception), and you need to write a second method, then call the
> > > second method, then debug the second method.
> > >
> > > So what's in rest? Arrays collection of warnings and errors. Changing
> > > return types or passing second-return by reference.
> > >
> > > [ Enum case ~ DTO output ] covers newly written code. Old code is
> > > uncovered. You have to rewrite a full tree, that's why some trick is
> > > necessary.
> > >
> > > I did it my way with an error bag stack. I enable it inside the
> function or
> > > in place I call the function. I want to share this experience, and
> imagined
> > > it would be better for all users. It could be done without 2 classes,
> 10
> > > functions and work with push/pop/current (closer to
> ob_start/ob_get_clean
> > > story).
> > > I guess it could be implemented if `raise` world will put any data to
> the
> > > current error bag in the stack. Exactly if the current error bag is
> present
> > > (declared manually like you can declare() strict types or ticks for
> some
> > > scope).
> > >
> > > I agree that there's more mandatory problems to solve that I didn't
> even
> > > know about.
> > > I tried to talk about error handling with a few developers, all of them
> > > recommend:
> > > 1. Use exceptions, don't make anything fresh
> > > 2. Do validation at the script start to reduce the count of errors
> later
> > >
> > > I've just encountered cases where bugs come from within - once you
> > > integrate a really bad external system with its own checks, which are
> > > described in hundreds of documents, I'm sure you'll encounter new bugs
> once
> > > the "working" code is released to production. And then you will need to
> > > quickly and easily reorganize it.
> > >
> > > And you can't.
> > > And you will be sad.
> > > And, "PHP moves differently" is a completely wrong principle, I
> believe in
> > > "watching for".
> > I think there's a subtle but important difference here between what
> you're describing as the problem and what you implied the solution was
> (which I then ran with).
> >
> > What you're talking about is trying to change the error handling model
> of existing code without changing function signatures.  There are only two
> possible ways to do that, both of them bad: Unchecked exceptions and
> globals.
> >
> > What I described, based on the syntax you offered, is checked
> exceptions, which necessarily means changing the function signature.  Error
> handling is part of the contract of a function.  If its error handling
> changes, it *should* have a signature change to indicate that.  (That
> unchecked exceptions do not do that is the problem with unchecked
> exceptions.)  So if "no changes to existing code" is the goal, checked
> exceptions as I describe them are not the answer you are looking for.
> >
> > It seems from your latest message that you're 

Re: [PHP-DEV] Feature request: https://github.com/php/php-src/issues/13301

2024-02-07 Thread Robert Landers
On Tue, Feb 6, 2024 at 9:22 PM Larry Garfield  wrote:
>
> On Tue, Feb 6, 2024, at 7:56 PM, Григорий Senior PHP / Разработчик Web wrote:
> > Thanks Larry, I will read both articles next weekend.
> >
> > Am not even talking about changing `throw` to `raise`.
> >
> > Am talking only about:
> > - production ready code
> > - that should be able to refactor with error collectors (that was not
> > implemented years ago)
> > - without touching return types
> > - without touching input arguments of existing code
> > - without possible code fall after throw exception: you have to try/catch
> > all places you use that function (sometimes you predict possible error, and
> > yes, write return class/enum to extend/refactor it later)
> > (and yes, if old code did not support returning null/null-object before -
> > you have to refactor return types then)
> >
> > While working with queues you have a list of tasks
> > - then you reduce it to smaller with reducer (unique/filter/merge)
> > - then do some queries
> > - then walk initial data using reduced results: copying reports to save
> > errors/warnings to each task separately
> >
> > It cannot be solved with exceptions. In addition, large arrays throw
> > exceptions that cause timeloss. It's definitely not a tool for.
> > Also your method could return many errors (today - only one
> > error/exception), and you need to write a second method, then call the
> > second method, then debug the second method.
> >
> > So what's in rest? Arrays collection of warnings and errors. Changing
> > return types or passing second-return by reference.
> >
> > [ Enum case ~ DTO output ] covers newly written code. Old code is
> > uncovered. You have to rewrite a full tree, that's why some trick is
> > necessary.
> >
> > I did it my way with an error bag stack. I enable it inside the function or
> > in place I call the function. I want to share this experience, and imagined
> > it would be better for all users. It could be done without 2 classes, 10
> > functions and work with push/pop/current (closer to ob_start/ob_get_clean
> > story).
> > I guess it could be implemented if `raise` world will put any data to the
> > current error bag in the stack. Exactly if the current error bag is present
> > (declared manually like you can declare() strict types or ticks for some
> > scope).
> >
> > I agree that there's more mandatory problems to solve that I didn't even
> > know about.
> > I tried to talk about error handling with a few developers, all of them
> > recommend:
> > 1. Use exceptions, don't make anything fresh
> > 2. Do validation at the script start to reduce the count of errors later
> >
> > I've just encountered cases where bugs come from within - once you
> > integrate a really bad external system with its own checks, which are
> > described in hundreds of documents, I'm sure you'll encounter new bugs once
> > the "working" code is released to production. And then you will need to
> > quickly and easily reorganize it.
> >
> > And you can't.
> > And you will be sad.
> > And, "PHP moves differently" is a completely wrong principle, I believe in
> > "watching for".
> I think there's a subtle but important difference here between what you're 
> describing as the problem and what you implied the solution was (which I then 
> ran with).
>
> What you're talking about is trying to change the error handling model of 
> existing code without changing function signatures.  There are only two 
> possible ways to do that, both of them bad: Unchecked exceptions and globals.
>
> What I described, based on the syntax you offered, is checked exceptions, 
> which necessarily means changing the function signature.  Error handling is 
> part of the contract of a function.  If its error handling changes, it 
> *should* have a signature change to indicate that.  (That unchecked 
> exceptions do not do that is the problem with unchecked exceptions.)  So if 
> "no changes to existing code" is the goal, checked exceptions as I describe 
> them are not the answer you are looking for.
>
> It seems from your latest message that you're describing more a generalized 
> version of `json_last_error()` and similar functions.  The problem there is 
> that such an API design is generally considered very poor practice outside of 
> C, because it's all necessarily based on globals and "hope you remembered to 
> check the thing that no one told you to check and is not even slightly 
> obvious to check".  That is not something I would want better support for in 
> the language at all.  There's probably cleaner ways to emulate it in 
> user-space, but that is for a particular application to sort out.  There's 
> definitely cleaner monadic solutions (which I've written before and are quite 
> neat) using a writer/logger monad, but that again doesn't meet your "don't 
> change existing code" requirement.  I don't think anything the language can 
> do will meet that requirement and be a good design.
>
> --Larry Garfield
>
> --