Question

The following code works and is clear, but it's also verbose. I suspect that there's a way to make it more terse, so that it could be skimmed quickly and it'd be more obvious what's happening.

// The functions return either `false`, or a valid URL.
$redirect = site_redirects( $domain, $_SERVER['REQUEST_URI'] );

if ( ! $redirect ) {
    $redirect = get_city_slash_year_url( $domain, $_SERVER['REQUEST_URI'] );
}

if ( ! $redirect ) {
    $redirect = unsubdomactories_redirects( $domain, $_SERVER['REQUEST_URI'] );
}

if ( ! $redirect ) {
    $redirect = get_canonical_year_url( $domain, $path );
}

if ( $redirect ) {
    header( 'Location: ' . $redirect );
}

As an example, here's something I tried that didn't work:

$redirect = 
    site_redirects( $domain, $_SERVER['REQUEST_URI'] )             ||
    get_city_slash_year_url( $domain, $_SERVER['REQUEST_URI'] )    ||
    unsubdomactories_redirects( $domain, $_SERVER['REQUEST_URI'] ) ||
    get_canonical_year_url( $domain, $path )
;

...but that just returns true or false, instead of the first truthy return value.

I know it'll vary somewhat from language to language, but I'm curious if there's a common pattern, or at least something common to C-based languages.

Was it helpful?

Solution

You can use the Ternary Operator:

$redirect = site_redirects( $domain, $_SERVER['REQUEST_URI'] ) ?:
            get_city_slash_year_url( $domain, $_SERVER['REQUEST_URI'] ) ?:
            unsubdomactories_redirects( $domain, $_SERVER['REQUEST_URI'] ) ?:
            get_canonical_year_url( $domain, $path ) ?:
            false ;

if ($redirect) header( 'Location: ' . $redirect );

It is "missing" the expression between ? and : for the alternate version of the Ternary operator and behaves as follows:

Expression expr1 ?: expr3 returns expr1 if expr1 evaluates to TRUE, and expr3 otherwise.

If you're worried about its "unexpected behavior", it has already been tested out 10 years ago:

// I couldn't find much info on stacking the new ternary operator, so I ran some tests:

<?php
echo 0 ?: 1 ?: 2 ?: 3; //1
echo 1 ?: 0 ?: 3 ?: 2; //1
echo 2 ?: 1 ?: 0 ?: 3; //2
echo 3 ?: 2 ?: 1 ?: 0; //3

echo 0 ?: 1 ?: 2 ?: 3; //1
echo 0 ?: 0 ?: 2 ?: 3; //2
echo 0 ?: 0 ?: 0 ?: 3; //3
?>

// It works just as expected, returning the first non-false value within a group of expressions.

I noticed that it has no test for an all false condition, so a quick test using this code confirms its behavior:

<?php 
        echo 0 ?: 0 ?: 0 ?: 0; // returns 0 as required
?>

Since you're working with strings, just note that false, "0", and "" all evaluates to a false. It will follow the logic of empty().

OTHER TIPS

I'm not familiar with PHP but if I were doing this in e.g. Python I would create a function like this

def get_first_truthy(*conditions):
    for condition in conditions:
        if condition:
            return condition

    return None

If lazy evaluation is important, you change this to accept a list of methods or lambdas.

Here's an example of how calls to that would look (again, in Python):

redirect = get_first_truthy(
  site_redirects(domain, _SERVER['REQUEST_URI'] ),
  get_city_slash_year_url(domain, _SERVER['REQUEST_URI']),
  unsubdomactories_redirects(domain, _SERVER['REQUEST_URI']),
  get_canonical_year_url(domain, path)
)

if redirect:
  header(f'Location: {redirect}')

For the lazy eval solution, I'm really unsure what is possible in PHP but here's what that could look like in Python:

def get_first_truthy(*conditions):
    for condition in conditions:
        result = condition()
        if result:
            return result

    return None

And the usage:

def lazy(func, domain, param):
  def do_eval():
     return func(domain, param)
  
  return do_eval

redirect = get_first_truthy(
  lazy(site_redirects, domain, _SERVER['REQUEST_URI']),
  lazy(get_city_slash_year_url, domain, _SERVER['REQUEST_URI']),
  lazy(unsubdomactories_redirects, domain, _SERVER['REQUEST_URI']),
  lazy(get_canonical_year_url, domain, path)
)

if redirect:
  header(f'Location: {redirect}')

If you wanted something more generic you could do this:

def lazy(func, *params):
  def do_eval():
     return func(*params)
  
  return do_eval

Again, I'm not sure this helps you in PHP but maybe you could use anonymous functions to get something similar.

I'm unfamiliar with php; however the logic looks like a long boolean OR expression. Maybe something like:

if ( ($redirect = site_redirects( $domain, $_SERVER['REQUEST_URI'] ))
  || ($redirect = get_city_slash_year_url( $domain, $_SERVER['REQUEST_URI'] ))
  || ($redirect = unsubdomactories_redirects( $domain, $_SERVER['REQUEST_URI'] ))
  || ($redirect = get_canonical_year_url( $domain, $path ))
) {
      header( 'Location: ' . $redirect );
      }
Licensed under: CC-BY-SA with attribution
scroll top