Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[5.6] Optional can be converted into string #23306

Closed
wants to merge 3 commits into from
Closed

[5.6] Optional can be converted into string #23306

wants to merge 3 commits into from

Conversation

TheDeadCode
Copy link
Contributor

Fix for #23303

@taylorotwell
Copy link
Member

Do you have a real-world use case?

@TheDeadCode
Copy link
Contributor Author

My own --

I use an external library and it uses a direct cast on the objects in a list, to populate different fields. It either takes null, three different types of objects, or a string to get the value.

We only implement those types of objects in a few places, but we use __toString everywhere else. optional() was perfect for us due to that, except that it lacked the ability to cast.

It can also potentially break the code if someone were to move from the instance of a specific object, to Optional, and direct cast it to a string, either in his own code or in an external library.

@BrandonShar
Copy link
Contributor

Based on the test, I don't think I understand the use case. An optional, after having a method called on it, is going to return either the expected result or swallow it and return nothing. Casting (string) optional($var) with your change doesn't seem to have any benefit for using the optional, at the end of the day you're just running (string) $var.

@TheDeadCode
Copy link
Contributor Author

The goal was to make the optional class as much compatible as possible with the underlying object.

@BrandonShar
Copy link
Contributor

Yes, but optional is used when you don't know if your variable contains an object or not. With your use case, optional doesn't actually do anything because the behavior is the same whether it's passed an object or null.

With your code:

$x = null;

(string) optional($x); // ""
(string) $x; // ""

Why even use optional here?

The normal usage is when you're doing something like calling a method optional($x)->someMethod() where having null would cause an error.

@Miguel-Serejo
Copy link

Miguel-Serejo commented Feb 27, 2018

@BrandonShar You only tested the null case. This is to fix the non-null case of casting optional to string.

>>> $user = App\User::find(1);
=> App\User {#878} //collapsed for brevity
>>> (string) optional($user);
PHP Recoverable fatal error:  Object of class Illuminate\Support\Optional could not be converted to string on line 1

@TheDeadCode
Copy link
Contributor Author

TheDeadCode commented Feb 27, 2018

Exactly what @36864 said. This is to make optional compatible with the underlying object, like I have said multiple times now.

When you cast null to a string, you get “”, which is the expected behaviour.

If you do not feel like making optional compatible with the underlying object as much as possible, then simply close this PR.

@BrandonShar
Copy link
Contributor

I must not be being clear...

Here's what you want to change optional to do:

$x = null;
(string) optional($x) // ""
$x = User::find(1);
(string) optional($x) // {"id": 1, ...}

And here's what happens if you don't use optional at all

$x = null;
(string) $x // ""
$x = User::find(1);
(string) $x // {"id": 1, ...}

So why are you using optional at all?

@Miguel-Serejo
Copy link

Consistency, mostly?

$x = optional($model);
$x->maybeDoSomething();
$service->print($x);

I'd also like to point out this PR, which is essentially the same type of addition (making optional work in a case where it wouldn't be needed at all): #22417

@BrandonShar
Copy link
Contributor

I wouldn't have merged #22417 either 😉

I understand your example now, I wasn't thinking of a situation like that. I would discourage storing optional values and keeping them, though; I don't think this is the only situation where it would behave strangely.

I didn't write the original optional code, but I've always assumed it was based on the & operator in ruby and have used it as such: just use it to swallow potential method call on null errors and don't actually hang on to the result long term.

@taylorotwell
Copy link
Member

@TheDeadCode can you share the actual code snippet demonstrating how you want to use this?

@taylorotwell
Copy link
Member

I'm still just confused on why you are echoing an optional result directly. Usually when optional is used it is to access some other property or method on the given value, not echo the optional itself.

@GrahamCampbell
Copy link
Member

NB, in most other languages, to string is not directly proxied in an optional. They usually wrap the string up so you know you printed an optional.

@taylorotwell
Copy link
Member

Closing pending inactivity. Feel free to re-open with more examples of how this would be used.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants