PHP Pipes in 156 Bytes
github.com
github.com
function slug(string $s) {
return pipe($s,
fn($s) => strtolower($s),
fn($s) => str_replace(" ", "-", $s)
);
}
slug("10 WAYS to EAT more HEALTHY"); // 10-ways-to-eat-more-healthy
I'm not sure I see how this example demonstrates the point of something like this.Surely this is simpler and more succinct?
function slug(string $s) {
return str_replace(" ", "-", strtolower($s));
}
Even if you wanted to break it up into two lines: function slug(string $s) {
$s = strtolower($s);
return str_replace(" ", "-", $s);
}
A better example might go a long way here.Edit: Never walk away to refill a coffee before pressing submit or the rest of HN will beat you to it. :P
I am a Bad Programmer (it's not my day job, though I have managed programmers for many years), so maybe I am just missing the point in examples like this - but I often find this is the case in many code samples for language features. They usually have a trite example that shows how it can work in a really basic case.
This is helpful from a purely technical level - as here, I can see what is going on neatly.
But they rarely seem to show it being used how the designer expects it to be used in the wild to save time, or increase productivity, or whatever. Like, why would anyone want to do this?
I would personally NEVER want to see a function like that in a codebase when it could be written so much more clearly as in your examples. Although I personally would prefer a third style:
function slug(string $s) {
$s = strtolower($s);
$s = str_replace(" ", "-", $s);
return $s;
}
... more verbose, but I never see the point in trying to save a line if it sacrifices even a small bit of readability. Again, as a Bad Programmer, I like things to be spelled out super clearly whenever possible, so maybe that's just me.Sure, the pipes example might look nifty, but from a practical viewpoint, it's just not that useful. Next thing you know, someone throws an eval into the mix by mistake, and we end up with unintended consequences.
function slug(string $s) {
$s = strtolower($s);
$s = str_replace(" ", "-", $s);
return $s;
}
And, if you need classes, aren't you better served with a Decorator implementation? I just don't see the point here. function cleanIdsTraditionally(array $input): array
{
return array_unique(array_filter(array_map('intval', $input)));
}
Here it is as the piped version: function cleanIdsWithPipe(array $input): array
{
return pipe($input,
fn($input) => array_map('intval', $input),
fn($input) => array_filter($input),
fn($input) => array_unique($input)
);
}
Here, I think the added context of the pipe negates the enhanced readability of having each method on its own line. Anything more complex than this would benefit from being piped, but at that point, it would probably be better to break the steps down into more discrete functions anyways.Overall, not a bad idea, but in practice, it would be hard to justify having around
$collection = new ArrayCollection([4,3,2,1]);
$collection->filter(fn($element) => $element % 2 == 0)
->map(fn($element) => $element+2)
->toArray();
It is pretty much like in JavaScript or C# with Linq, but with less features.But you can implement this yourself using
- ArrayInterface, Traversable, Countable, etc.
- generators / iterators (yield)
It's not that hard. There is also YaLinqo[2][1] https://www.doctrine-project.org/projects/doctrine-collectio... [2] https://github.com/Athari/YaLinqo
function pipes(callable ...$pipes): Closure
{
return function($value) use ($pipes) {
foreach ($pipes as $pipe) {
$value = call_user_func($pipe, $value);
}
return $value;
};
}
This makes the pipes reusable and makes it so that functions that take only a single argument can be passed as a plain string: $sanitize = pipes('trim', 'htmlspecialchars');
$title = $sanitize($title);
$body = $sanitize($body);
While also preserving the ability to pass a closure when you need multiple arguments.Right now I see an example of how to write unreadable and hard-to-debug code
Being a senior PHP dev I would not let pass such code into our master branch, mainly because it is syntactic sugar that does not help with a specific problem and also does not attribute to a clearer and readable code at all.
Remember: In a company, where we rely on the code to earn our living the two factors readbilty and testabilty are the single most important ones. Because if you are off to holiday and your coworkers can't get a grasp of your (seemingly) clever code, than the whole company has a problem.
function pipe($callables) {
return array_reduce($callables, fn($carry, $callable) => call_user_func($callable, $carry));
}
Whenever a method merely calls other methods in sequence, returning the result of the last call, it's just too easy for me to simply use a pipe function. I guess it's mostly a matter of preference.https://gist.github.com/runekaagaard/5a172eccfa2fdbcd625a3a0...
<?php
function pipe(...$args) {
// Retrive first argument as initial value
$value = array_shift($args);
// Call the functions passing $value and assign its return
foreach($args as $func) $value = $func($value);
// Return computed value
return $value;
}
echo pipe("10 WAYS to EAT more HEALTHY",
fn($s) => strtolower($s),
fn($s) => str_replace(" ", "-", $s)
);
Works just as well.Here's my version in only 66 bytes, what do I win? ;)
<?php function pipe($v,...$p){foreach($p as$f)$v=$f($v);return$v;} <?php $pipe=fn($v,...$p)=>array_reduce($p,fn($a,$f)=>$f($a),$v);