Showing posts with label PHP. Show all posts
Showing posts with label PHP. Show all posts

Tuesday, 20 July 2010

Aptana for PHP

My favorite IDE has support for PHP again!

It's still in early stage of development, but it looks promising. Feel free to try it, it usable at this stage.

http://www.aptana.com/products/studio3/download

Test it, report bugs - and make suggestions! Suggestions will help Aptana team to make this product better.

https://aptanastudio.tenderapp.com/discussions/suggestions

Sunday, 11 April 2010

PHP benchmarks (part 3)

There is third and final post about PHP benchmarks.


Test:
double (")    vs.    single (') quotes

This one doesn't need to be tested, since single quotes are faster (but not so much as people would think), since double quotes strings do parse to find variables and special characters while single quotes don't.

Here is simple example to demonstrate that:

$var = 123;
$single_quotes = '$var\n';
$double_quotes = "$var\n";
echo $single_quotes;
echo $double_quotes;
echo 'Test';

And the result is:

$var\n123 Test

So, as you can see, single quote string isn't parsed, so PHP variables in that string aren't substituted with their string representation, and special characters like new line character is left as is - backslash followed by "n" character. While, string in double quotes is parsed and variables are replaced with their string representation.
Notice space between "123" and "Test" in place where should have been a new line. Actually, there is a new line and you can see that "Test" is in line next to line where "123" string is, if you check page source (Ctrl + U in Firefox, View -> Page source ... in some other browsers). This behaviour is characteristic of HTML language (all white space characters are represented as a space).

What would be interesting to test here? Well, single versus double quotes aren't correct subject to test since they do different thing and are being used in different situations (yes, both can be used in same situation, but then mostly you'll use single quotes since they are little faster). Here, the real subject of testing should be some real use case, I'll take, for example, some dummy SQL query building process:

$max = 100; 
$var1 = 123;
$var2 = 456;
$var3 = 789;
$var4 = 987;
$start = microtime();
for($i = 0; $i < $max; ++$i) {
$where = $var1 . ', ' . $var2 . ', ' . $var3 . ', ' . $var4;
}
echo 'Total test 1: ' . (microtime() - $start) . '<br>';

$var1 = 123;
$var2 = 456;
$var3 = 789;
$var4 = 987;
$start = microtime();
for($i = 0; $i < $max; ++$i) {
$where = "$var1,  $var2, $var3, $var4";
}
echo 'Total test 2: ' . (microtime() - $start) . '<br>';

$var1 = 123;
$var2 = 456;
$var3 = 789;
$var4 = 987;
$start = microtime();
for($i = 0; $i < $max; ++$i) {
$where = "{$var1}, {$var2}, {$var3}, {$var4}";
}
echo 'Total test 3: ' . (microtime() - $start) . '<br>';

$var1 = 123;
$var2 = 456;
$var3 = 789;
$var4 = 987;
$start = microtime();
$arr = array($var1, $var2, $var3, $var4);
for($i = 0; $i < $max; ++$i) {
$where = implode(', ', $arr);
}
echo 'Total test 4: ' . (microtime() - $start) . '<br>';

And the typical result is:

Total test 1: 0.000194

Total test 2: 0.000158

Total test 3: 0.000152

Total test 4: 0.000162

As you can see, using single quotes can sometimes even be slower (using implicitly ... with some other operation, to be precise). Here, slowness isn't product of single quotes, it's a product of string concatenation, which takes more time than double string parsing, or even "implode" of different array's parts (sometimes I use array to store values which I later implode in SQL statements, it's clean and simple solution).
So ... be aware of what you're doing and look at big picture not just micro-picture (or should I say ... micro-results). Don't just take benchmarks for granted - think (and benchmark) for yourself!


Next test is:

Test:
isset()    vs.    empty()    vs.    is_array()


Well, this test doesn't make much sense since these three things are checking for different things:

  • "isset" check if variable is set and is not NULL
  • "empty" checks if variable is empty. That is equivalent with boolean cast of particular variable. You should check PHP documentation regarding "empty" to see what values are considered to be empty (zero as a string for example is considered empty, empty string also, so check and remember, it's useful to know)
  • "is_array" checks if variable is array
So, for example, you can't use "empty" if you want to see if variable is an array. Use whatever is suitable, not whatever is the fastest.

Notice: "is_array" throws notice, while "isset" and "empty" does not. So, you should check if variable is set before checking if it's an array: 

if (isset($var) && is_array($var))

Doing checking this way, if variable is not set, "isset" will return "FALSE" and second evaluation argument ("is_array") won't be evaluated since PHP is optimized not to do that (FALSE && anything[TRUE or FALSE] is FALSE ... see logical operator truth table).

Notice's notice: it is often used OR operator in some cases. For example:

mysql_connect(...) OR die(...);
What does this mean? It's similar optimization as for AND logical operator, but it is different in one thing - second evaluation argument is evaluated only if the first one return FALSE. If first returns TRUE, the second one isn't evaluated since TRUE || anything is TRUE. You can see that in this simple example:

$test = 'Test';
TRUE OR ($test = 'OR');
echo $test; // echoes 'Test'


$test = 'Test';
FALSE OR ($test = 'OR');
echo $test; // echoes 'OR'

You can, for practice, do something similar for AND logical operator.


Next is final test in this series of posts:

Test:
switch/case    vs.    if/elseif
"==" vs. "===" 

There are some misconceptions here. "===" (strict) operator is faster than "==" (loose) operator, that for sure. But, they shouldn't be subject for testing, since they do different thing, for example:

"0" == FALSE // true
"0" === FALSE // false 

Strict comparison operator checks if variables are of same type and than it compares their values. Loose comparison operator behaves different, it checks if variable types are identical, if not it casts one variable type to other's type and then comparison is done.

Type conversion is done in next manner: if comparison involves number or a numerical string, they are converted to numbers and then compared numerically.

Notice: try this: var_dump("0" == "00");

Loose comparison is done in switch statements, so you should be aware of what you're comparing, because any string that doesn't can't be cast to numeric value is being cast to the zero!

 $abc = 'abc';
switch ($abc) {
case 0:
    echo 'Zero found';
    break;
case 'abc':
    echo 'abc found';
    break;
}

'abc' won't ever be found, since variable $abc will be converted to it's numeric representation and that would be 0 (zero) and it will be matched in first "case".


There are a lot more cases of comparison. You can find good references at PHP documentation:

http://php.net/manual/en/language.operators.comparison.php


Type of Operand 1 Type of Operand 2 Result
null or string string Convert NULL to "", numerical or lexical comparison
bool or null anything Convert to bool , FALSE < TRUE
object object Built-in classes can define its own comparison, different classes are uncomparable, same class - compare properties the same way as arrays (PHP 4), PHP 5 has its own explanation
string , resource or number string , resource or number Translate strings and resources to numbers, usual math
array array Array with fewer members is smaller, if key from operand 1 is not found in operand 2 then arrays are uncomparable, otherwise - compare value by value (see following example)
array anything array is always greater
object anything object is always greater





Now, you should only know how type are converted between them and that can also be found in PHP documentation:

http://www.php.net/manual/en/language.types.type-juggling.php#language.types.typecasting

For practice, you can make a lot of examples, here are some:

$one = '';
$two = 0;
$three = '0';
echo "'' == 0"; // true
var_dump($one == $two);
echo "'' == '0'"; // false, of course
var_dump($one == $three);
echo "0 == '0'"; // true
var_dump($two == $three); 


'1' == true
bool(true)

1 == 'true'
bool(false)

1 == true
bool(true)

'true' == true
bool(true)

'0' == true
bool(false)

'0' == false
bool(true)

'false' == true
bool(true)

'false' == false
bool(false)

etc. 


There is one more thing that could be tested - "echo" vs. "print" (with and without use of output buffering, see "ob_start" for example), but I'll leave that to the reader in hope he can make his own benchmark after this series of my blog posts. I hope you have learnt some things.


Here are some more optimization tips:


  • don't make your own functions, use PHP native wherever possible
  • use "@" - suppress warning operator - when you really need it - best is to avoid it, since it slows down application
  • when echo-ing more value, use "," instead of "." (echo $var1, $var2, $var3 - instead of - echo $var1 . $var2 . $var3 . ...)
  • don't use: $array[key] - use $array['key']. $array[key] is slower and error prone (if key is not constant ~ is not defined ~ it is considered as a string
  • use: if (isset($array['key'])) instead of: if (array_key_exists('key', $array)), but only if you are sure that any of $array values won't be NULL, since then 'key' will exist but "isset" will return FALSE
  • ++$i is faster than $i++
  • use "===" instead of "==" where ever possible (and not just for speed reasons)

And they are plenty more, I'm sure. I would like to hear any of them, so please send your advices to my email address or comment here.


At the end remember - these are only micro-optimizations. There are much better ways to optimize your application (if it's slow) than this tips. This is just a learning game to better know the language! I hope you've learnt something from this. :)

Friday, 9 April 2010

PHP benchmarks (part 2)

Let's continue ...

Next test is:

Test
Is it worth the effort to calculate the length of the loop in advance?
E.g. "$size=count($array); for ($i=0; $i<$size; $i++)" instead of "for ($i=0; $i<count($array);$i++)"

This test is good in terms of optimization (precalculation of array's size is worth, because size of an array is being calculated every time at new iteration), but one thing has to be mentioned here, assumption is that array doesn't change in terms of adding or deleting items, because "count" would be different from $size and these two loops would do different things. So, you should be aware of what you're doing because you could get unexpected results.


Test
$obj = new SomeClass()    vs.    $obj =& new SomeClass() using the =&-ref-operator

 You should be careful with this, because they are not identical. I'll show you in one example:

class A {
public $p = 1;
}

$a = new A;
$b = $a;
$c = & $a;

echo $a->p . '<br>';

$b->p++;

echo $a->p . '<br>';

$c->p++;

echo $a->p . '<br>';


echo '<br>##############<br>';

echo '<br>$a = NULL;<br>';

$a = new A;
$b = $a;
$c = & $a;


$a = NULL;

var_dump($a);
echo '<br>';

var_dump($b);
echo '<br>';

var_dump($c);
echo '<br>';

echo '<br>##############<br>';

echo '<br>$b = NULL;<br>';

$a = new A;
$b = $a;
$c = & $a;

$b = NULL;

var_dump($a);
echo '<br>';

var_dump($b);
echo '<br>';

var_dump($c);
echo '<br>';

echo '<br>##############<br>';

echo '<br>$c = NULL;<br>';

$a = new A;
$b = $a;
$c = & $a;

$c = NULL;


var_dump($a);
echo '<br>';

var_dump($b);
echo '<br>';

var_dump($c);
echo '<br>';


And the results are:


1
2
3

##############

$a = NULL;
NULL
object(A)#2 (1) { ["p"]=> int(1) }
NULL

##############

$b = NULL;
object(A)#1 (1) { ["p"]=> int(1) }
NULL
object(A)#1 (1) { ["p"]=> int(1) }

##############

$c = NULL;
NULL
object(A)#2 (1) { ["p"]=> int(1) }
NULL

As you can see, variable's reference acts as described in my previous post - as variable alias (one more name). As for object, object's reference is just an identifier of particular object. There can be multiple identifiers, just like references, but difference is that references are closely bonded to variable and object's reference to object's identifier. Here is small graphic illustration:

$a = $c => $obj
$b => $obj

Here is one more example to illustrate that, I'll use "unset" to show the difference (and to show difference between "$a = NULL" and "unset($a)"):

echo '<br>##############<br>';

echo '<br>unset $a<br>';

$a = new A;
$b = $a;
$c = & $a;


unset($a);

var_dump($a);
echo '<br>';

var_dump($b);
echo '<br>';

var_dump($c);
echo '<br>';

echo '<br>##############<br>';

echo '<br>unset $b<br>';

$a = new A;
$b = $a;
$c = & $a;

unset($b);

var_dump($a);
echo '<br>';

var_dump($b);
echo '<br>';

var_dump($c);
echo '<br>';

echo '<br>##############<br>';

echo '<br>unset $c<br>';

$a = new A;
$b = $a;
$c = & $a;

unset($c);

var_dump($a);
echo '<br>';

var_dump($b);
echo '<br>';

var_dump($c);
echo '<br>';

 And the results are:


##############

unset $a
NULL
object(A)#1 (1) { ["p"]=> int(1) }
object(A)#1 (1) { ["p"]=> int(1) }

##############

unset $b
object(A)#2 (1) { ["p"]=> int(1) }
NULL
object(A)#2 (1) { ["p"]=> int(1) }

##############

unset $c
object(A)#1 (1) { ["p"]=> int(1) }
object(A)#1 (1) { ["p"]=> int(1) }
NULL

Now, let's go back to previous example and see what happens when setting variables to "NULL".
Here are results once more:

##############

$a = NULL;
NULL
object(A)#2 (1) { ["p"]=> int(1) }
NULL

##############

$b = NULL;
object(A)#1 (1) { ["p"]=> int(1) }
NULL
object(A)#1 (1) { ["p"]=> int(1) }

##############

$c = NULL;
NULL
object(A)#2 (1) { ["p"]=> int(1) }
NULL

So...


$a = $c => $obj
$b => $obj

$c = NULL

$a = $c => NULL 
$b => $obj

unset($c)


$a => $obj
$b => $obj



You can draw other situations for practice. :)


When I first observed how "unset($a)" and "$a = NULL" work, it seemed to me that they behave in identical way:


$a = 'Test';
unset($a);
var_dump($a);

This produces "NULL", so I thought "$a = NULL" would produce same result. But they behave different in the background. I haven't looked at PHP's internals, but I suppose "unset" deletes variable from symbol table, while setting to "NULL" doesn't delete variable from symbol table, it just setts it's value to "NULL". This can be illustrated by next example:

$a = 'Test';

echo '<pre>';
print_r(get_defined_vars());
echo '</pre>';


echo '<br>Unset $a<br>';
unset($a);

echo '<pre>';
print_r(get_defined_vars());
echo '</pre>';


echo '<br>$a = NULL<br>';

$a = 'Test';

$a = NULL;

echo '<pre>';
print_r(get_defined_vars());
echo '</pre>';

And result is:

Array
(
    [GLOBALS] => Array
        (
            [GLOBALS] => Array
 *RECURSION*
            [_POST] => Array
                (
                )

            [_GET] => Array
                (
                )

            [_COOKIE] => Array
                (
                )

            [_FILES] => Array
                (
                )

            [a] => Test
        )

    [_POST] => Array
        (
        )

    [_GET] => Array
        (
        )

    [_COOKIE] => Array
        (
        )

    [_FILES] => Array
        (
        )

    [a] => Test
)

Unset $a
Array
(
    [GLOBALS] => Array
        (
            [GLOBALS] => Array
 *RECURSION*
            [_POST] => Array
                (
                )

            [_GET] => Array
                (
                )

            [_COOKIE] => Array
                (
                )

            [_FILES] => Array
                (
                )

        )

    [_POST] => Array
        (
        )

    [_GET] => Array
        (
        )

    [_COOKIE] => Array
        (
        )

    [_FILES] => Array
        (
        )

)

$a = NULL
Array
(
    [GLOBALS] => Array
        (
            [GLOBALS] => Array
 *RECURSION*
            [_POST] => Array
                (
                )

            [_GET] => Array
                (
                )

            [_COOKIE] => Array
                (
                )

            [_FILES] => Array
                (
                )

            [a] => 
        )

    [_POST] => Array
        (
        )

    [_GET] => Array
        (
        )

    [_COOKIE] => Array
        (
        )

    [_FILES] => Array
        (
        )

    [a] =>  
) 

Be careful when using "isset". From PHP documentation (http://www.php.net/manual/en/function.isset.php):

Determine if a variable is set and is not NULL.

This means - is defined in symbol table and it's value is not NULL. There is a difference between this two conditions in terms of producing a notice as we can see here:

echo $a;
$a = NULL;
echo $a;

First "echo" produces notice, while second one does not (because there is no $a variable in symbol table - it is not defined as notice says).


That's all for this time, more info coming!

Tuesday, 6 April 2010

PHP benchmarks (part 1)

Recently I've stumbled upon several PHP benchmark tests. I've found that a lot of these tests were inaccurate or based on false conceptions.
Unfortunately, none of them mentioned what PHP version are they using (and maybe some extra stuff could be useful also). I'll use PHP 5.3/Apache 2.2 on my Windows XP SP3.


Let's bring up some light. I'll begin with loops!

LOOPS


Question: What is the best way to loop a hash array?


Answer: In short - there is no one best way to loop an array. It depends on what do you intend to do with array (read, write/modify).


In one benchmark regarding array values reading (and not writing) these were the tests:

+ 100 % 1: foreach($aHash as $val); Total time: 0[ms]
+ 1196 % 2: while(list(,$val) = each($aHash)); Total time: 1[ms]
+ 2176 % 3: foreach($aHash as $key=>$val); Total time: 2[ms]
+ 3017 % 4: while(list($key,$val)= each($aHash)); Total time: 3[ms]
+ 2300 % 5: foreach($aHash as $key=>$val) $tmp[] = & $aHash[$key]; Total time: 3[ms]
+ 2461 % 6: while(list($key) = each($aHash)) $tmp[]=&$aHash[$key]; Total time: 3[ms]
+ 819 % 7: Get key-/ value-array: foreach($aHash as $key[]=>$val[]); Total time: 1[ms]
+ 864 % 8: Get key-/ value-array: array_keys() / array_values() Total time: 1[ms]
+ 839 % 9: STRANGE: This is the fasetest code when using the the &-ref-operator (to avoid copying)
$key = array_keys($aHash);
$size = sizeOf($key);
for ($i=0; $i<$size; $i++) $tmp[] = &$aHash[$key[$i]]; Total time: 1[ms]

And this tests and conclusions are incorrect since they don't do identical thing.
For example, one can benchmark:

++$i;   VS  $i++;

since result will be correct. But benchmarking:

$j = $i++;   VS    $j = ++$i;

isn't correct since final result isn't identical (the latter $j will be greater).

So, one should be aware of what he is benchmarking, so he could draw right conclusions from benchmark results.


Now ... why above mentioned benchmarks aren't correct?
Because they are comparing different things. Take "foreach" loop for example:

1: foreach($aHash as $val);
3: foreach($aHash as $key=>$val);
5: foreach($aHash as $key=>$val) $tmp[] = &$aHash[$key];

How could this be compared? First two aren't identical since there is one extra assignment ($key). The third ... well, I'm not sure what author intended to do with this, but it isn't good at all since there are more operations involved beside looping - creating $tmp array's new element, getting $aHash element with $key key and aliasing $aHash array as new array element.

One important misconception is there:
STRANGE: This is the fasetest code when using the the &-ref-operator (to avoid copying)
& - reference operator actually doesn't prevent copying (actually, it has different semantic meaning and behaviour ... see "PHP reference"). When looping through array, it's value copy isn't made unless array is being modified (see "PHP lazy copying" or "PHP copy on write"). So, reading array values won't make a copy and using &-reference operator in foreach loop that doesn't modify an array actually slows down looping since variable alias has to be created in symbol table (see "PHP symbol table").

So ... in short - using reference will modify original array in one writes to referenced array's value, not using won't (that's why values are being copied when writing/modifying, it's language optimization so you don't have to worry about that).

If someone doesn't understand & operator ... it simply creates variable alias (one more name). Try to imagine that like some thing that has more than one name:

$myFruit = 'Apple';
$yourFruit = & $myFruit;

var_dump($yourFruit);
//prints 'Apple'


Here, your fruit is 'Apple'.
Actually, I am You in the background. :)

Try this:

$yourFruit = 'Orange';
var_dump($myFruit);
//prints 'Orange'
So, you can see these variables acts as one.




My tests are divided into two sections. The first one uses array's key, the second one doesn't. Why to test like this? Because of above mentioned fairness - loop has to do identical thing in different ways so results can be compared. One should store array's key into variable ($key) when it will be used.

$hashA = array();
$hashB = array();
$hashC = array();
$a = 'a';
$b = 'b';
$c = 'c';
$max = 10000;

for ($i = 0; $i < $max; ++$i) {
$hashA[$a . $i] = $i;
}

$start = microtime();

foreach ($hashA as $key => $value) {}

echo microtime() - $start, '<br><br>';

# NEXT TEST
for ($i = 0; $i < $max; ++$i) {
$hashB[$b . $i] = $i;
}

$start = microtime();
@reset($hashB);
while(list($key, $value) = each($hashB)) {}

echo microtime() - $start, '<br><br>';

# NEXT TEST
for ($i = 0; $i < $max; ++$i) {
$hashC[$c . $i] = $i;
}

$start = microtime();

$key = array_keys($hashC);
$size = count($key);
for ($i=0; $i<$size; ++$i) {
                        $key = $keys[$i];
                $value = $hashC[$key];
}

echo microtime() - $start, '<br><br>';

Typical results are:

0.002062

0.014654

0.005652

Someone will probably notice "@reset" (see "PHP @" and "PHP reset"). Yes, that adds some extra time to the "while" loop (but it doesn't make a difference). "@reset" is commonly used before "while" loop, so I think it's better to put it in the test because it shows real use case.


Tests without array's key:


$hashA = array();
$hashB = array();
$hashC = array();
$a = 'a';
$b = 'b';
$c = 'c';
$max = 10000;

for ($i = 0; $i < $max; ++$i) {
$hashA[$a . $i] = $i;
}

$start = microtime();

foreach ($hashA as $value) {}

echo microtime() - $start, '<br><br>';

# NEXT TEST
for ($i = 0; $i < $max; ++$i) {
$hashB[$b . $i] = $i;
}

$start = microtime();
@reset($hashB);
while(list(, $value) = each($hashB)) {}

echo microtime() - $start, '<br><br>';

# NEXT TEST
for ($i = 0; $i < $max; ++$i) {
$hashC[$c . $i] = $i;
}

$start = microtime();

$keys = array_keys($hashC);
$size = count($keys);

for ($i=0; $i<$size; ++$i) {
$value = $hashC[$keys[$i]];
}

echo microtime() - $start, '<br><br>';

The typical results are:

0.000784

0.014069

0.005436


Let's move on to the "modify loop" ...

+ 272 % 1: foreach($aHash as $key=>$val) $aHash[$key] .= "a"; Total time: 3[ms]
+ 128 % 2: while(list($key) = each($aHash)) $aHash[$key] .= "a"; Total time: 1[ms]
+ 100 % 3: STRANGE: This is the fasetest code :
$key = array_keys($aHash);
$size = sizeOf($key);
for ($i=0; $i<$size; $i++) $aHash[$key[$i]] .= "a"; Total time: 1[ms]
These tests are more or less correct, but one version of "foreach" loop is missing. If we want to modify array's values, why not use & operator? In above tests it's used to read values, but not for modifying values - and that is wrong in semantic context. It should be used only when we need to modify original array and not opposite (just when reading array's values).

Here are my tests:

$hashA = array();
$hashB = array();
$hashC = array();
$hashD = array();

$a = 'a';
$b = 'b';
$c = 'c';
$d = 'd';
$max = 10000;

for ($i = 0; $i < $max; ++$i) {
$hashA[$a . $i] = $i;
}

$start = microtime();

foreach ($hashA as $key => $value) {
$hashA[$key] = 'A';
}

echo microtime() - $start, '<br><br>';

# NEXT TEST
for ($i = 0; $i < $max; ++$i) {
$hashB[$b . $i] = $i;
}

$start = microtime();
@reset($hashB);
while(list($key) = each($hashB)) {
$hashB[$key] = 'B';
}

echo microtime() - $start, '<br><br>';

# NEXT TEST
for ($i = 0; $i < $max; ++$i) {
$hashC[$c . $i] = $i;
}

$start = microtime();

$keys = array_keys($hashC);
$size = count($keys);

for ($i=0; $i<$size; ++$i) {
$hashC[$keys[$i]] = 'C';
}

echo microtime() - $start, '<br><br>';

# NEXT TEST
for ($i = 0; $i < $max; ++$i) {
$hashD[$d . $i] = $i;
}

$start = microtime();

foreach ($hashD as &$value) {
$value = 'D';
}

echo microtime() - $start, '<br><br>';
// dump $hashD if you don't believe it's modified
//var_dump($hashD);

Typical results are:

0.007736

0.015848

0.006368

0.002416 

So, one can see that the missing "foreach" loop is actually the fastest! :)




CONCLUSION


There is no need to complicate things. Just use what is proper to use:


  • if one reads array values use "foreach($array as $value)" or "foreach($array as $key => $value) if one needs array's keys also
  • if one writes/modifies original array values use "foreach($array as &$value)" or "foreach($array as $key => &$value) if one needs array's keys, so that values are written using referencing variable $value (and not $array[$key])


FINAL WORDS

If you want to optimize your PHP scripts by changing loop type ("while" to "foreach") - don't do that, especially if your application isn't slow. These optimizations are micro-optimizations and they are made as conclusion from results under certain environment and conditions and may not produce same results in some other environment and conditions. 
In real world situations, PHP will rarely be the slowest part of your application - database design is most common point where to search for speeding up your application ... amount of HTML, JS, CSS are also place where you could speed up user experience. For more frequently used applications, there is APC, load balancing, caching and so on.

This should be guidelines how to write PHP scripts from basics and to understand some of PHP basics. More will come up soon!