views:

256

answers:

4

So I was thinking one way that you can bring method chaining into PHP with the built-in global functions would be to "borrow" the |> (pipe) operator from F#. It would pipe the results on the left into the first parameter of the function on the right. Of course PHP would have to revisit the parameter order of some of their functions.

This would allow you to write:

function StrManip($val) {  
  return str_repeat(strtolower(trim($val)),2);  
}

Like this:

function StrManip($val) {  
  return $val |> trim() |> strtolower() |> str_repeat(2);  
}
+2  A: 

I've never seen that annotation before, but it sure looks nice. Somehow reminds me of functional programming (maybe it's just me).

But I've actually stopped hoping that the PHP group would make such fundamental changes to the language. They seem to play catch-up with other languages - they look at what other people are doing, and then they pick what they like, and what suits the(ir) PHP world. The object orientedness and namespaces, as examples, are quite recent features, when you look at the competition.

I, personally, have hoped to see named parameters (á la "strpos(needle=$foo, haystack=$bar)") since I saw them in action in Python. Since then, the PHP design group has actually refused to implement it.

Henrik Paul
to bad they refused them, they seem to make code more readable
Jacco
I agree with the reasoning. I don't think named parameters a *good* thing.
BobbyShaftoe
well, they would at least render the inconsistencies between functions' argument passing (see e.g. explode() vs strpos()) inconsequential. Instead of remembering which arguments to pass and in which order, you just need to know which arguments to pass. I guess this is a matter of taste, then.
Henrik Paul
Agreed. I personally would like to have the option.
J Cooper
+2  A: 

Something much like that can be accomplished using fluent object methods. For example:

class Foo 
{
    public function bar()
    {
        echo 'Hello<br/>';
        return $this;
    }

    public function bar2()
    {
        echo 'Goodbye<br/>';
        return $this;
    }   
}

$foo = new Foo();

$foo->bar()->bar2();

Outputs the following:

Hello
Goodbye

Noah Goodrich
Yeah, but note that what he described is much more generic; this requires making a special class with methods with the appropriate side-effects each time
J Cooper
An it requires PHP to go totally 100% OOP which they don't seem interested in doing. Or at least not designing in from the ground up.
tyndall
+7  A: 

It looks like what he wants is a String class with methods that mirror the builtin functions. This is a guess, but maybe you could use the __call magic method to do the work like this:

(untested)

class String {
   private $_value = '';
   public function __construct($value) {
      $_value = $value;
   }
   public function __call ($name, $arguments) {
      return new String($name($_value, $arguments));
   }
}

$string = new String($string);
echo $string->trim()->strtolower()->str_repeat(2);

You would have to do some parsing to get the $arguments part to work, and it would create a lot of objects when you chain the methods, but in theory this should get you some functionality you are looking for.

willoller
A: 

This is interesting. What about this solution?

function pipe($v, $fs)
{   
    foreach(explode('|', $fs) as $f)
    {
        if(strpos($f, '[') === FALSE){
            $v = call_user_func($f, $v);
        }else{
            list($fun, $args) = explode('[', trim($f), 2);
            $args = explode(',', str_replace('!', $v, substr($args, 0, -1)));
            $v = call_user_func_array($fun, $args);
        }
    }
    return $v;
}


echo pipe(' test STRING??', 'trim|strtolower|str_repeat[!,3]|str_replace[string,cheese,!]');

This prints out

test cheese??test cheese??test cheese??

The function pipe takes two arguments. The first is the initial value and the second is a pipe-delimited list of functions to which to apply to the first argument. To allow for multi-argument functions, the [ and ] characters can be used (like parentheses are used in PHP). The placeholder '!' can be used to specify where to insert the strings along the chain.

In the above example, the following happens:

trim(' test STRING??') => 'test STRING??'
strtolower('test STRING??') => 'test string??'
str_repeat('test string??', 3) => 'test string??test string??test string??'
str_replace('string', 'cheese', 'test string??test string??test string??') => 'test cheese??test cheese??test cheese??'

The characters [, ], and ! were chosen arbitrarily. Also, this doesn't allow you to use commas in the function arguments, although it could be expanded to allow this.

Interesting question!

(Idea for '|' delimited list of functions taken from Code Igniter, although they don't do variable replacement. It could also easily be a string array, but the array() constructor is verbose)

Bill Zeller
I thought of this one myself but didn't write any code to test out the idea, but love what you did. I did not have the right ideas about how to do the params... my equivalent was pipe(' SomeThing ','trim|strtolower) ... I would only add quotes to the strings - see next comment
tyndall
echo pipe(' test STRING??', 'trim|strtolower|str_repeat[!,3]|str_replace["string","cheese",!]');
tyndall
+1 - I'll have to look at what Code Igniter did in this respect. I have seen other frameworks like CakePHP use shortcut alias for certain functions to make function wrapping less ugly.
tyndall
I have also thought of using a shortcut function to create an object (like jQuery). But if you stack this object full of functions you pay a price for instantiating it.
tyndall