Hello,
From time to time I need to write a few lines of code that usually look ridiculous:
$var = $input === ‘yes’ ? ‘yes’ : ’no’
$var = $input !== ‘yes’ ? ’no’ : $yes
$var = $input > 10 ? 10 : $input
$var = max(-10, min($input, 10)
and many other variations.
In Kotlin, I can use coerceIn() extension function with strings / numbers / comparables, which allows me to write such lines more readable.
I suggest to add such function to PHP. The examples above may look like the following
$var = coerce($input, variants: [“yes”, “no”], default: “yes”);
$var = coerce($input, min: 0, max: 10, default: 5);
$var = coerce($input, min: 0, max: 10, default: 5);
For sure, that could be different functions not to introduce another overloading function. Or range arguments could be replaced with range(0, 10) function.
This letter is an intent to start discussion of any possible ways of developing this idea.
If we agree that the function has enough value to be bundled I’ll create RFC to push the idea further.
So what do you think?
Best regards,
Dmitrii Derepko.
@xepozz
Hi Dmitry,
I suggest to add such function to PHP. The examples above may look like the following
$var = coerce($input, variants: [“yes”, “no”], default: “yes”);
$var = coerce($input, min: 0, max: 10, default: 5);
$var = coerce($input, min: 0, max: 10, default: 5);For sure, that could be different functions not to introduce another overloading function. Or range arguments could be replaced with
range(0, 10)function.
My first thought was that the min/max variant would be covered by the recently-accepted clamp() function: https://wiki.php.net/rfc/clamp_v2 Looking closer, I see that you want to default to a specific value, not the nearest, so it's not quite the same.
I think combining both tasks into one function is definitely the wrong approach. PHP doesn't have function overloading, and although you can partially stimulate it with nullable and optional parameters, the whole thing ends up very messy compared to just having separate functions.
Using range() to pass in an array would be less efficient than min and max, but maybe good enough for small ranges. Perhaps in future we will have a separate "lazy range" type, which could then be handled as a special case.
In general, I don't think it's a function that I'd use often, but it seems a reasonable enough addition to the language.
Thanks,
Rowan Tommins
[IMSoP]
Hi Dmitry,
I suggest to add such function to PHP. The examples above may look like the following
$var = coerce($input, variants: [“yes”, “no”], default: “yes”);
$var = coerce($input, min: 0, max: 10, default: 5);
$var = coerce($input, min: 0, max: 10, default: 5);For sure, that could be different functions not to introduce another overloading function. Or range arguments could be replaced with
range(0, 10)function.My first thought was that the min/max variant would be covered by the recently-accepted clamp() function: https://wiki.php.net/rfc/clamp_v2 Looking closer, I see that you want to default to a specific value, not the nearest, so it's not quite the same.
I think combining both tasks into one function is definitely the wrong approach. PHP doesn't have function overloading, and although you can partially stimulate it with nullable and optional parameters, the whole thing ends up very messy compared to just having separate functions.
Using
range()to pass in an array would be less efficient than min and max, but maybe good enough for small ranges. Perhaps in future we will have a separate "lazy range" type, which could then be handled as a special case.In general, I don't think it's a function that I'd use often, but it seems a reasonable enough addition to the language.
Thanks,
Rowan Tommins
[IMSoP]
Thanks for your thoughts.
I agree that it’s better to have a few separate functions for different use cases.
Regarding the lazy ranges, basically, it’s kind of iterable, but with bounds.
I think it could be done as the others are: new IntRangeIterator(start: 0, end: 10, inclusive: true) / or as a new function range_iterator / or as a new flag argument in the original range function.
So, there are could be a function with:
- manual range bounds
— strings
— ints
— enums? - iterator range bounds
— IntRangeIterator(start: 0, end: 10, inclusive: true)
— CharRangeIterator(start: ‘A', end: ‘D', inclusive: true)
— Any otheriterable, including Generators and regular arrays
Actually, looks quite reasonable to re-use iterables. Nice catch, I really like it.
Best regards,
Dmitrii Derepko.
@xepozz
trivial to make in userland.
how about making a composer coerce package first,
give it some time, check if it becomes popular,
and if it does catch on, reconsider adding it to core?
trivial to make in userland.
Sure, almost everything is trivial to make in userland and re-use as a function.
how about making a composer coerce package first,
give it some time, check if it becomes popular,
and if it does catch on, reconsider adding it to core?
I don’t think so. There’s no node-js world with left-pad function.
People prefer to write plain php instead of re-using external function that’s needed to be downloaded and correctly loaded with autoload. Too much effort to re-use.
Moreover, event if a function is quite popular, it doesn’t mean it should be bundled: dd / dump / u / any Laravel global functions that’s users think it’s bundled.
I think it’s better to grep the world with structural search and find some cases:
- condition($a) ? $a : expr()
- if (condition($a)) { $a = expr() }
With more or less popular use-cases:
- $a == ‘desc’ ? ‘desc’ : ‘asc’
- $a == ’true’ ? ’true' : ‘false’
- $a > 10 ? 10 : ($a < 0 ? 0 : $a)
- max(0, min($a, 10)
- in_array($key, $values) ? $key : $default
- array_key_exist($key, $values) ? $values[$key] : $default
- isset($values[$key]) ? $values[$key] : $default
- any similar
It could be done if I prepare RFC and it will be necessary. Firstly, I’d like to discuss the idea itself.
Best regards,
Dmitrii Derepko.
@xepozz
Hello,
From time to time I need to write a few lines of code that usually look
ridiculous:$var = $input === ‘yes’ ? ‘yes’ : ’no’
$var = $input !== ‘yes’ ? ’no’ : $yes
$var = $input > 10 ? 10 : $input
$var = max(-10, min($input, 10)and many other variations.
In Kotlin, I can usecoerceIn()extension function with strings /
numbers / comparables, which allows me to write such lines more readable.I suggest to add such function to PHP. The examples above may look like
the following$var = coerce($input, variants: [“yes”, “no”], default: “yes”);
$var = coerce($input, min: 0, max: 10, default: 5);
$var = coerce($input, min: 0, max: 10, default: 5);
btw many of these are already covered by filter_var,
$var = $input === ‘yes’ ? ‘yes’ : ’no’
$var = $input !== ‘yes’ ? ’no’ : $yes
$var = coerce($input, variants: [“yes”, “no”], default: “yes”);
$var = coerce($input, min: 0, max: 10, default: 5);
is very close to
$var = filter_var($input,FILTER_VALIDATE_BOOL);
$var = !filter_var($input,FILTER_VALIDATE_BOOL);
$var = filter_var($input,FILTER_VALIDATE_BOOL,
['options'=>['default'=>true]]);
$var = filter_var($input, FILTER_VALIDATE_INT, ['options'=>['min_range'=>0,
'max_range'=>10, 'default'=>5]]);
but if your syntax idea cover stuff like
$var = coerce($input, variants: [“yes”, “no”, "maybe"], default: “yes”);
then filter_var does not cover it (well, you could get creative with
FILTER_VALIDATE_CALLBACK, but that would be crazy, array_search would be
better lel)
but even so, your proposed syntax is certainly prettier than filter_var.