40+ Useful Php tips for beginners – Part 2

By | April 7, 2012

Part 1

11. Do not gzip output in your application , make apache do that

Thinking of using ob_gzhandler ? No dont do that. It doesnt make sense. Php is supposed to write your application. Dont worry about how to optimise data transfer between server and browser inside Php.

Use apache mod_gzip/mod_deflate to compress content via the .htaccess file.

12. Use json_encode when echoing javascript code from php

There are times when some javascript code is generated dynamically from php.

$images = array(
 'myself.png' , 'friends.png' , 'colleagues.png'
);

$js_code = '';

foreach($images as $image)
{
$js_code .= "'$image' ,";
}

$js_code = 'var images = [' . $js_code . ']; ';

echo $js_code;

//Output is var images = ['myself.png' ,'friends.png' ,'colleagues.png' ,];

Be smart. use json_encode :

$images = array(
 'myself.png' , 'friends.png' , 'colleagues.png'
);

$js_code = 'var images = ' . json_encode($images);

echo $js_code;

//Output is : var images = ["myself.png","friends.png","colleagues.png"]

Isn't that neat ?

13. Check if directory is writable before writing any files

Before writing or saving any file , make sure you check that the directory is writable or not , and flash an error message if it is not. This will save you a lot of "debugging" time. When you are working on a linux , permissions have to be dealt with and there would be many many permission issues when directories would not be writable , files would not be readable and so on.

Make sure that your application is as intelligent as possible and reports the most important information in the shortest time.

$contents = "All the content";
$file_path = "/var/www/project/content.txt";

file_put_contents($file_path , $contents);

That is totally correct. But has some indirect problems. The file_put_contents may fail for a number of reasons :

  • Parent directory does not exist
  • Directory exists , but is not writable
  • File locked for writing ?

So its better to make everything clear before writing out to a file.

$contents = "All the content";
$dir = '/var/www/project';
$file_path = $dir . "/content.txt";

if(is_writable($dir))
{
    file_put_contents($file_path , $contents);
}
else
{
    die("Directory $dir is not writable, or does not exist. Please check");
}

By doing this you get the accurate information that where is a file write failing and why

14. Change permission of files that your application creates

When working in linux environment , permission handling can waste a lot of your time. Hence whenever your php application creates some files do a chmod over them to ensure they are "accessible" outside. Otherwise for example the files may be created by "php" user and you are working as a different user and the system wont let you access or open the file , and then you have to struggle to get root privileges , change the permissions of the file and so on.

// Read and write for owner, read for everybody else
chmod("/somedir/somefile", 0644);

// Everything for owner, read and execute for others
chmod("/somedir/somefile", 0755);

15. Don't check submit button value to check form submission

if($_POST['submit'] == 'Save')
{
    //Save the things
}

The above is mostly correct , except when your application is multi-lingual. Then the 'Save' can be many different things. How would you compare then. So do not rely on the value of submit button. Instead use this :

if( $_SERVER['REQUEST_METHOD'] == 'POST' and isset($_POST['submit']) )
{
    //Save the things
}

Now you are free from the value the submit button

16. Use static variables in function where they always have same value

//Delay for some time
function delay()
{
    $sync_delay = get_option('sync_delay');
    	
    echo "<br />Delaying for $sync_delay seconds...";
    sleep($sync_delay);
    echo "Done <br />";
}

Instead use static variables as :

//Delay for some time
function delay()
{
    static $sync_delay = null;
	
    if($sync_delay == null)
    {
	$sync_delay = get_option('sync_delay');
    }
	
    echo "<br />Delaying for $sync_delay seconds...";
    sleep($sync_delay);
    echo "Done <br />";
}

17. Don't use the $_SESSION variable directly

Some simple examples are :

$_SESSION['username'] = $username;
$username = $_SESSION['username'];

But this has a problem. If you are running multiple applications on the same domain , the session variables my conflict. 2 different applications may set the same key name in the session variable. Take for example , a frontend portal , and the backend management application , on the same domain.

Hence use application specific keys with wrapper functions :

define('APP_ID' , 'abc_corp_ecommerce');

//Function to get a session variable
function session_get($key)
{
    $k = APP_ID . '.' . $key;
   
    if(isset($_SESSION[$k]))
    {
        return $_SESSION[$k];
    }
    
    return false;
}

//Function set the session variable
function session_set($key , $value)
{
    $k = APP_ID . '.' . $key;
    $_SESSION[$k] = $value;
    
    return true;
}

18. Wrap utility helper functions into a class

So you have a lot of utility functions in a file like :

function utility_a()
{
    //This function does a utility thing like string processing
}

function utility_b()
{
    //This function does nother utility thing like database processing
}

function utility_c()
{
    //This function is ...
}

And you use the function throughout your application freely. You may want to wrap them into a class as static functions :

class Utility
{
    public static function utility_a()
    {
        
    }
    
    public static function utility_b()
    {
        
    }

    public static function utility_c()
    {
        
    }
}

//and call them as 

$a = Utility::utility_a();
$b = Utility::utility_b();

One clear benefit you get here is if php has inbuilt functions with similar names , then names will not conflict.
Another perspective , though little advanced is that you can maintain multiple versions of the same class in the same application without any conflict. Its basically encapsulation , nothing else.

19. Bunch of silly tips

  • Use echo instead of print
  • Use str_replace instead of preg_replace , unless you need it absolutely
  • Do not use short tags
  • Use single quotes instead of double quotes for simple strings
  • Always remember to do an exit after a header redirect
  • Never put a function call in a for loop control line.
  • isset is faster than strlen
  • Format your code correctly and consistently
  • Do not drop the brackets of loops or if-else blocks.
    Do not code like this :

    if($a == true) $a_count++;

    Its absolutely a WASTE.

    Write

    if($a == true)
    {
        $a_count++;
    }

    Dont try to make your code shorter by eating up syntax. Rather make your logic shorter.

  • Use a proper text editor which has code highlighting. Code highlighting helps to create lesser errors.

20. Process arrays quickly with array_map

Lets say you want to trim all elements of an array. Newbies do it like this :

foreach($arr as $c => $v)
{
	$arr[$c] = trim($v);
}

But it can more cleaner with array_map :

$arr = array_map('trim' , $arr);

This will apply trim on all elements of the array $arr. Another similar function is array_walk. Check out the
documentation on these to know more.

21. Validate data with php filters

Have you been using to regex to validate values like email , ip address etc. Yes everybody had been doing that. Now lets
try something different, called filters.

The php filter extension provides simple way to validate or check values as being a valid 'something'.

22. Force type checking

$amount = intval( $_GET['amount'] );
$rate = (int) $_GET['rate'];

Its a good habit.

23. Write Php errors to file using set_error_handler()

set_error_handler() can be used to set a custom error handler. A good idea would be write some important errors in a file for logging purpose

24. Handle large arrays carefully

Large arrays or strings , if a variable is holding something very large in size then handle with care. Common mistake is to create a copy and then run out of memory and get a Fatal Error of Memory size exceeded :

$db_records_in_array_format; //This is a big array holding 1000 rows from a table each having 20 columns , every row is atleast 100 bytes , so total 1000 * 20 * 100 = 2MB

$cc = $db_records_in_array_format; //2MB more

some_function($cc); //Another 2MB ?

The above thing is common when importing a csv file or exporting table to a csv file

Doing things like above can crashs scripts quite often due to memory limits. For small sized variables its not a problem , but must be avoided when handling large arrays.

Consider passing them by reference , or storing them in a class variable :

$a = get_large_array();
pass_to_function(&$a);

by doing this the same variable (and not its copy) will be available to the function. Check documentation

class A
{
    function first()
    {
        $this->a = get_large_array();
        $this->pass_to_function();
    }

    function pass_to_function()
    {
        //process $this->a
    }
}

unset them as soon as possible , so that memory is freed and rest of the script can relax.

Here is a simple demonstration of how assign by reference can save memory in some cases

<?php

ini_set('display_errors' , true);
error_reporting(E_ALL);

$a = array();

for($i = 0; $i < 100000 ; $i++)
{
	$a[$i] = 'A'.$i;
}

echo 'Memory usage in MB : '. memory_get_usage() / 1000000 . '<br />';

$b = $a;
$b[0] = 'B';

echo 'Memory usage in MB after 1st copy : '. memory_get_usage() / 1000000 . '<br />';

$c = $a;
$c[0] = 'B';

echo 'Memory usage in MB after 2st copy : '. memory_get_usage() / 1000000 . '<br />';

$d =& $a;
$d[0] = 'B';

echo 'Memory usage in MB after 3st copy (reference) : '. memory_get_usage() / 1000000 . '<br />';

The output on a typical php 5.4 machine is :

Memory usage in MB : 18.08208
Memory usage in MB after 1st copy : 27.930944
Memory usage in MB after 2st copy : 37.779808
Memory usage in MB after 3st copy (reference) : 37.779864

So it can be seen that in the 3rd copy which was by reference memory was saved. Otherwise in all plain copies memory is used up more and more.

25. Use a single database connection, throughout the script

Make sure that you use a single connection to your database throughout your script. Open a connection right in the beginning and use it till the end , and close it at the end. Do not open connections inside functions like this :

function add_to_cart()
{
    $db = new Database();
    $db->query("INSERT INTO cart .....");
}

function empty_cart()
{
    $db = new Database();
    $db->query("DELETE FROM cart .....");
}

Having multiple connections is a bad idea and moreover they slow down the execution since every connection takes time to create and uses more memory.

Use the singleton pattern for special cases like database connection.

Part 3

About Silver Moon

A Tech Enthusiast, Blogger, Linux Fan and a Software Developer. Writes about Computer hardware, Linux and Open Source software and coding in Python, Php and Javascript. He can be reached at [email protected].

10 Comments

40+ Useful Php tips for beginners – Part 2
  1. Sander Marechal

    > 24. Handle large arrays carefully

    PHP uses copy-on-write internally. Using references does not save memory. Only use references you want to change the input variable of a function.

  2. EllisGL

    “Use the singleton pattern for special cases like database connection.”

    I would avoid using singletons for a number of reasons. One being if you set it up wrong, you are tied to only one database through out your app. The second one is Unit Testing. Makes it damn near impossible to test it properly.

    1. Silver Moon Post author

      “One being if you set it up wrong, you are tied to only one database through out your app.”

      – If needed then there should be multiple database connections , but as long as working with a single database there is no need. Its not a rule, just an approach, the use of which very much depends on the requirements.

      Moreover, its possible to work with multiple databases using a single connection :

      INSERT INTO `database2`.`table_name` (………

      It will work even if your mysqli object is connected to `database1`

      “The second one is Unit Testing. Makes it damn near impossible to test it properly.”

      – Testing , development and deployment are different scenarios. The database class can be configured to be non-singleton during testing and singleton when deployed. Its just a change of configuration.

      1. smassey

        “Testing , development and deployment are different scenarios. The database class can be configured to be non-singleton during testing and singleton when deployed. Its just a change of configuration.”

        Would that not defeat the entire purpose of unit testing, if you’re going to deploy different implementations to production than what you actually test ??? Sorry, but I must agree with EllisGL, singletons are a no-go if you want proper/strict unit testing. There are many more elegant and testable ways to achieve the exact same behavior without touching static properties. (giving them a parent scope and “lazy loading” the connections for example).

        Next I would like to know why you state “Do not use short tags”. Is there a reason for this ? As of 5.4 they’re even enabled by default.

        For the rest I really enjoyed this article, great job.

        1. Silver Moon Post author

          I agree with your and EllisGL’s views on unit testing with singletons. They are to be avoided for proper unit testing.

          Short tags should be avoided because :

          1. If short tags are disabled on a certain hosting , then the whole code will be echoed to screen.

          Php 5.4 has enabled “short echo tags” <?= by default , not "short tags" <? .
          So if 'short_open_tag = Off' in php 5.4 the code inside short tags will not run , just echo as plain text.

          1. EllisGL

            I personally think short tags are awful. And the support of is something I frown at. Equals sign should be an assignment, so one could read this as “Question mark equals something?!”. Are we so lazy, that writing out is too much for us to bear?

      2. EllisGL

        If the second database is on the same server, then that would work OK. But if not, there’s where the problem lies. It’s been an issue I’ve hit several times.

Leave a Reply

Your email address will not be published. Required fields are marked *