Solving the Lack of Comma Operator in PHP

This is somehow a follow up of my previous post Making Decisions Inside Function Calls

As I continued developing I hit yet another problem. How do we execute more than one expression inside the ternary operator?

When you are developing there are times when you want to be able to do stuff like this:

if(condition){
  func();
  func2();
}else{
  someotherFunc();
}

this is something I’m sure you’ve encountered many times. In my case, I’m using CORE. Most CORE functions expect a string as their first parameter. For example:

div(
  'this is the content of the div'
);

and most functions return a string too!, so we can do something like this:

div(
  p('this is a paragraph')
);

the p function returns a string that has the text we passed to it wrapped in <p></p> tags. This is a pretty smart think to do because we can nest function calls like this:

div(
  h1(
    spam(
      a(
        'Introduction', '#nogo'
      )
    )
  )
  .p(
    'Hello there, my name is '
    .strong('Buzu')
    .' nice to meet you.'
  )
)

It is a really nice way to develop websites. And when we add the ability to make decisions inside the function calls as we saw in the previous post, this becomes really powerful. But what happens when you want to do more than one expression?

If php had a comma operator, you would do something like this:

div(
  condition ?
    expression_1, expression_2, expression_3
  :
    expression_4, expression_5
);

However, if you do that in php, all you will get is an error.

It was suggested to me to use a lambda. At first I thought it was a nice idea, and felt stupid for not thinking about it myself, but then I quickly remembered why that was out of the question:

div(
  (condition ?
    function(){
      expression_1;
      expression_2;
      expression_3;
    }
  :
    function(){
      expression_4;
      expression_5;
    }
  )
);

After the conditional is evaluated, you end up with something like this:

div(
  function(){...}
);

And that throws you an error because the function cannot be converted into the string that div expects.

So, there is our problem.

The solution can be quite easy depending on what you are trying to do. In my case, the expressions are just function calls (I guess they are not really expressions, but lets just think they are). We already know we can execute as many function calls as we want as long as they return a string so we can concatenate them as a single string which is the parameter that we are expecting. That is why this is possible:

div(
  p('text')
  .p('text')
  .p('text')
  .p('text')
);

But sometimes we want to execute some other arbitrary functions, maybe functions that take care of some setup that is necessary before we can start using some other functions. For example, if you are developing a wordpress theme, sometimes you need to call functions that take care of populating global variables that are used by some other functions like the_author(). So we want to create something like this:

div(
  have_posts() ?
    the_post() //takes care of setting up some info that we will need next
    loadFunction('the_author')
  :
    ''
);

If you try that out, you will get an error. there is no way to insert those two function calls inside the ternary operator. At least no way that I’m aware of. The solution would be to concatenate them so they become one single expression. But you should not just concatenate them,since you don’t know what kind of stuff you could get back from the_post() now or in the future. You could end up with some weird result like:

‘1 Buzu’
or
‘Array() Buzu’

What you want to do is execute the_post() but mute it’s output whatever it might be.

Fortunately we have buffers in php. So the solution could be as simple as doing:

div(
  have_posts() ?
    mute('the_post') //takes care of setting up some info that we will need next
    .loadFunction('the_author')
  :
    ''
);

In theory, this should solve the problem. The mute function would be simply something like this:

function mute(func, args=array()){
  ob_start();
  call_user_func_array($func, $args);
  ob_end_clean();
  return '';
}

I have not tested this. It is just a theory that I will test later, but I think it should solve the problem.

There are still more problems to solve. For example, what if you want to do this:

div(
  condition ?
    $a = $b + $c;
    func($a);
  :
    func()
);

I think this problem could be harder to solve, and it might be just better to let some of the logic happen outside function calls.

What do you think?

3 thoughts on “Solving the Lack of Comma Operator in PHP

  1. Your problem is that you need to have a block construct inside expressions. Imperative languages treat statements and expressions differently and make this difficult while functional languages have a simple uniform syntax: everything is an expression and returns a value and expression can be nested arbitrarily. It’s a simple and powerful idea, isn’t it?

    You cannot use lambda functions because AFAIK PHP does not allow you to define a lambda function and call it right away in one instruction, without storing the function pointer into a variable first. This limitation of PHP is quite annoying. E.g. in Lisp or Scheme you can do:

    ((lambda (x) (* x x)) 5)

    and you get 25 when this expression gets evaluated.

    In JavaScript the same is:

    (function(x) { return x * x })(5);

    but the closer you can get to it in PHP is:

    $f = function ($x) { return $x * $x; };
    $f(5);

    Something like:

    (function ($x) { return $x * $x; })(5);

    is not syntactically allowed in PHP.

    You could implement a PHP function that takes a variable number of arguments and resembles the (progn expr1 … exprn) Common Lisp form to define a block of code. This evaluates all arguments but returns only the value of the last one as the value of the full expression. Btw it is advised against abusing it in a functional programming style, because you usually want to decompose your problem into independent pieces and using too much progns calls means your procedures are probably too big.

    What you need to implement such things is the ability to treat code like data and PHP, unlike Lisp and other good functional languages, lacks decent support for that. In PHP you could pass the code to execute as a string and use eval. But there is a major drawback. This way you will be delaying any syntax check until execution time, which makes your programs more difficult to debug. Syntax highlight in your editor won’t work properly either. You really need a way to mark a piece of code as data, but this requires a major change of the PHP language.

    By comparison Common Lisp has a data mode: you can treat a piece of code as data simply by prefixing it with a quote (‘) e.g. for the purpose of delayed execution. The Lisp compiler/interpreter checks for correctness, it is not a string (which Lisp also has). This is the advantage of homoiconic languages. I was a PHP adept, but after I learned Lisp, I began to dislike all languages having an involved syntax with no or poor support for multi-paradigm programming.

    • Hello Antonio,
      Nice to see you here again. Indeed, a self-executing pattern was something that I tried at some point, but it does not work in php, like you already mentioned. In this circumstances, I always stop to realise once again that in fact php is a better language than php, despite all the bad things people say about javascript. There are very interesting patterns that can be done in javascript but not in php, and this is one instance.
      Unfortunately right now I can’t change php for other language since I’m working with wordpress. I would have to redo everything I’ve done so far, and at this point that is simply not an option.
      I will definitely be checking out the link you shared with us. It looks really interesting. Like I said before on a previous comment, I am considering lisp, or python. Python is in consideration merely because it is a language that is getting a lot of interest from the community, and also because is the language that people use to write gedit plugins, which is something that I would like to do at some point even if it is just as an exercise.
      I use vim though, but the vim extensions are something I wanted to do a long time ago when I used gedit as my primary text editor.

Comments are closed.