-
Notifications
You must be signed in to change notification settings - Fork 11.4k
[8.x] Support value callback arguments #36506
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
[8.x] Support value callback arguments #36506
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👎 The point of this method is to unwrap thunks. If you have a callable with params, just call it... $value(...$args)
.
Hey @GrahamCampbell, I know how to pass params to a callback. I am looking for the exact functionality that this PR allows to avoid making the type check myself. |
In my code I use this a lot: /** @var string|callable: string */
public $default;
// ...
if (! $value) {
$value = is_callable($this->default)
? ($this->default)($this, $foo);
: $this->default;
} With this PR I could do value($this->default, $this, $foo); Which is much more readable. It does the type check for me. I don't need any conditionals, I can just trust that it will run the callback with the given parameters if it's a callback, and if it's not, it just returns the value. I think that the entire purpose of If the argument against this is
Then you might as well say
And open a PR to remove the helper entirely. |
FWIW it'd be nice if the
Happy to hear any feedback about this change. As I said, in my packages and apps I use this pattern a lot, but I also never typehint |
It is important that it is not callable. If the value is a string like |
Then people using value where they wanted a callable as the value, can't do this anymore. |
Certainly cannot do this on 8.x. |
@GrahamCampbell why can't do it on 8.x? It's a global function - there is no way to override it? |
Current implementation:
Callable + not string check:
Bolded options are the only ones that would change. So the only breaking changes would be where people expected callables to be treated as values, but now they'd be treated as callbacks. That's a valid point, and there may be cases where this would cause breaking changes. But at the same time I seriously doubt that anyone would be actually affected. You'd need code like this: class MyCallback
{
public function __invoke() {
return 'foo';
}
}
$object = new MyCallback;
$closure = function ($args) {
return new MyCallback;
};
value($object, 'args'); // returns $object
value($closure, 'args'); // executes $closure which returns $object Which would be extremely ambiguous. One type of callable returns itself and another one gets executed. Plus, very few people knew about So I agree with @GrahamCampbell that it would technically be a breaking change (sudden unexpected change in behavior, even if you can override it in your own helpers file), but I can't think of a legitimate case where anyone would be affected by this. A developer who'd be aware of such obscure internal helpers wouldn't write code where one type of callable executes and another type is returned, they'd use a proper type check. So IMO that change would be very low risk. |
I can't tell what criteria you consider as "recent", but I use this helper a lot since when I started developing with Laravel (2015). I have seen usage in lots of projects, and many local Laravel developers I talk with use it. I was even introduced to this helper by a peer. Most common usage I've seen is to allow lazy evaluation of parameters on a service class' method.
Agree with @GrahamCampbell on this, one project I worked with and migrated to Laravel 8 just at the end of last year would certainly break. That project had a custom rule-based engine and accepted tuples (array callables), among other values, that should be evaluated later. Don't blame me, I was just hired to add a feature on that project. Shared just to point I've seen a project that would break with this change.
@stancl if you can share how to do it I would really appreciate. I needed this in the past and failed as it seemed to me composer autoloaded files from dependencies before the project's ones. I even just tried it again and got this error: > Illuminate\Foundation\ComposerScripts::postAutoloadDump
PHP Fatal error: Cannot redeclare value() (previously declared in /home/rodrigo/code/test/vendor/laravel/framework/src/Illuminate/Collections/helpers.php:182) I added a |
What exactly would break? Were you calling |
Well I can't share the exact code as it is from a client. But I will try to describe it. There are many Both If a model, passes all When applying an action, it iterates through each Also, those collected "tuple" callables are later called with the container ( Reason they can be out-of-order is because that project had a front-end that allowed users to build custom actions. I would do some stuff differently, but as I said I was just hired to add a feature and help migrate to Laravel 8, but again I just wanted to share a case I've seen recently that would break with the discussed change. Sorry if description is not clear enough, I am working on improving my English skills. But I hope you could see the use case. Also @stancl , if you can share how to override a global helper I would really appreciate, sorry if it sounded I was being ironic or something like that, if that is why you didn't answer it wasn't my intention, I am not a native speaker. But that is something I really needed in a previous project (migrating a legacy project to Laravel) and couldn't find a way to do so. If you think this is not the best place to share it, my twitter handle is the same as my github's. Thanks in advance. |
One more thing: I am not opposed on the change per se. I actually find it very useful and more intuitive on usage. Also I am not talking about the changes from this PR, but from that future changes discussed about accepting callables other than I am just saying I agree it is a breaking change on a minor/patch release. As some developers relying on the old behavior would be surprised with the change. In the usage I described, they can very easily add a local helper to hold the current behavior. |
This addition allows the developer to pass arguments to a
value()
helper callback.