Codular

HomeWriters RSS

PHP Tips and Tricks

Introduction

In previous articles we've touched on some major sections such as MySQLi, Classes and cURL. There are a lot of other tips and tricks that you should look at, and a few of them are covered below, a couple of which are transferrable between languages.

Ternary Operators

A ternary operator is a different way to layout a simple if statement. Let's take a look at one and then break it down. We'll just use a simple check to see if a GET parameter is set and not empty, if it is we will default to the word John, otherwise use the value that was set as the GET parameter.

$name = (!empty($_GET['name'])? $_GET['name'] : 'John');

This might look complex to begin with but there are three sections to a ternary operator:

  1. The conditional !empty($_GET['name'])
  2. The true result $_GET['name']
  3. The false result 'John'

The ternary operator will return either the true or false conditional, and therefore it will be assigned to $name. If we write this as a normal if statement we'd have one of the following:

if(!empty($_GET['name'])){
    $name = $_GET['name'];
}else{
    $name = 'John';
}

// Or

$name = 'John';
if(!empty($_GET['name'])){
    $name = $_GET['name'];
}

The two above and the ternary operator will all end up with $name having something assigned to it.

Nesting

While not advisable, it is possible to nest ternary operators within each other much like you would with standard if statements, or to form a long string of if...else if...else if...else statements.

Ternary operators can be very helpful and clean up code, but don't over complicate them otherwise your code might become inundated with large amounts of complex rediculousness that will get you hunted down by a violent psychopath.

Class Autoloading

To make use of a class file, you have to ensure that the class you're using is available within the page that you're using it. In most cases this will be as easy as you just including the PHP file that contains the class.

But what if we have a very large number of classes that we could potentially use within one or many sections of our code? Well, we could include all of them within a common header file, or only include the ones that we know that we're going to use on that page. However, we then need to remember to include new classes whenever we want to use a different one etc.

So instead of including classes that might not get used, or we might remove later, we can employ class autoloading. When we autoload classes we can write what will happen - this might be to just throw an error to let us know that we've not included the class file, or, as in most cases, we make the function include the file that we need.

The Code

Here we'll be using the PHP function spl_autoload_register(), we'll only be interested in the first parameter, but there are two others that you can define if you wanted the function to behave differently. I'll jump straight into how to use it:

function loadMyClass($class){
    echo 'We are loading class: ' . $class;
    include_once('classes/' . $class . '.inc.php');
    echo 'Class loaded.';
}

spl_autoload_register('loadMyClass');

This will pass the name of the class that we're trying to load as the first parameter of the function that we specified. As of PHP 5.3.0 we are able to use anonymous functions, basically a function thas has no name:

spl_autoload_register(function ($class){
    echo 'We are loading class: ' . $class;
    include_once('classes/' . $class . '.inc.php');
    echo 'Class loaded.';
});

Which will work exactly the same as the method of implementation above. So now in future, we don't need to include the class files that we'll be using as this function will run if the class is undefined, include the class and then the instantiation will be called.

Dynamic Variables

Sometimes we want to be able to dynmically define a variable, or refer to a variable based on a user's input. Let's start with this code:

$myname = 'Michael';
$yourname = 'Ben';
if($_GET['whatname'] == 'your'){
    echo $yourname;
}else if($_GET['whatname'] == 'my'){
    echo $myname;
}else{
    echo 'No Name';
}

To use the value of a variable to then form another variable we use double dollar signs $$ so for example we could do $who = 'myname'; then echo $$who. This will echo out the value of $myname.

Break it down like this (exemplary code, not actual working code):

$who = 'myname';
$$who = $'myname';
$$who = $myname;
echo $$who; // would return 'Michael'

In reference to the code above we could look to use something along the lines of the following for very dynamically defined variables:

$who = $_GET['whatname'] . 'name';
if(isset($$who)){
    echo $$who;
}else{
    echo 'No Name';
}

As with ternary operators, you should use these loosely, as in most situations there's not much need for them, but you will most probably find some crazy-ninja somewhere who uses this notation.

Referencing

Passing variables by reference, is a way to pass variables into functions so that the function can alter the original variable without having to return anything or define it as global etc. A function parameter that is going to be passed in as a reference is preceeded by an ampersand (&). Let's go with an example:

function lowercase(&$string){
    $string = strtolower($string);
}

$name = 'STEPHEN';
lowercase($name);
echo $name; // returns stephen

What you can see is that where we've called the lowercase() method and passed in $name, the function has altered the actual string that we passed in, as within the function $string becomes $name.

There are advantages of using references, for example you don't have to return anything from the function, nor do you have to look to define them as globally accessible.

Arrays

References are super awesome when you use them with arrays. Let's say we have a function that sets the first item in any array to potato - because you know, it'll be the most helpful function ever:

function potatoArray(&$array){
    $array[0] = 'potato';
}

$nonpotato = array(
    'john',
    'andrew',
    'cheese'
);

potatoArray($nonpotato);

print_r($nonpotato); // This will now have changed 'john' to 'potato'

References are very powerful things, and could be used extensively. You'll find them used with the array_walk() method other some other array methods that PHP have.

Relative Time Calculation

Everywhere you look people love their relative times, they're on Facebook, they're in most Twitter apps and they're here on Codular. Codular isn't too fussed about the specific time of when an action was made and so we have come up with a special class with handle the relative date for us.

We define a list of the days that exist, and then do some logic to find out what to display. We firstly check if it's today or yesterday, obviously returning the respective term. We then look to see if the date falls in the last 7 days (less than 8 days), this is so that we can display last Monday, last Sunday etc. But obviously the 'Last' prefix can only apply to one week.

Our method takes a second parameter with is a fallback format, this is the format that we use when the date falls out of the 'Last' date range. The first parameter is a simple UNIX timestamp.

<?php

class TimeClass {

    private static $days = array(
        'Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'
    );

    /**
     * relativeTime()
     * @param int $time
     * @param string $format
     */
    public static function relative($time, $format = 'jS F Y'){
        if(date('d/m/Y', $time) === date('d/m/Y')){
            return 'Today';
        }else if(date('d/m/Y', $time) === date('d/m/Y', time() - 3600 * 24)){
            return 'Yesterday';
        }else if((time() - $time) < 3600 * 24 * 8){
            return 'Last ' . self::$days[date('w', $time)];
        }else{
            return date($format, $time);
        }

    }

}

Usage would be as simple as doing:

echo TimeClass:relative(time());

That will always output Today as we are using the current timestamp.

Relative date calculations can be pretty smple, another that is commonly used is to round to the nearest multiple of a time frame - ie days, weeks, months years etc. Below is a quick function to finish off with that will do exactly that up to 10 years in time then fall back to a date:

<?php

function relativeTime($timestamp, $format = 'Y-m-d H:i'){
    $dif = time() - $timestamp;

    $dateArray = array(
        "second" => 60,     // 60 seconds in 1 minute
        "minute" => 60,     // 60 minutes in 1 hour
        "hour" => 24,       // 24 hours in 1 day
        "day" => 7,         // 7 days in 1 week
        "week" => 4,        // 4 weeks in 1 month
        "month" => 12,      // 12 months in 1 year
        "year" => 10        // Up to 10 years
    );

    foreach($dateArray as $key => $item){
        if($dif < $item)
            return $dif . ' ' . $key . ($dif == 1? '' : 's') . ' ago';
        $dif = round($dif/$item);
    }
    return date($format, $timestamp);
}
Tag: PHP