Sunday, February 28, 2010

Singleton is bad !!

An interesting suggestion emerged from some speakers (1 and 2) of the last PHP UK conf is: do not use the Singleton design pattern !!


At the beginning it made me a little astonished as it's one of the most widely used design patterns, in addition ZF and lots of other projects use it. However, after a while I agreed the idea. Singleton actually had created some problems when I had to do some class testing and refactoring in some PHP code.


Why is it not a good practice ? Singleton is appropriate when dealing with threads (JAVA, C#), but as a matter of fact in PHP applications it's used just as a global constant and it creates dependency injection. That's a bad practice as it couples the components/classes and usually makes difficult unit testing, refactoring and structural changes.

class A {
public function f(){
$c1 = c1::GetInstance(); #bad !!
# use $c1
$c2 = c2::GetInstance(); #bad !!
# use $c2
}
}

What's the alternative ? Simply, instead of retrieving the instance in the method of the class, retrieve it from an internal class field after it has been set by the constructor.

class A {
private $c1;
private $c2;

public function __constructor(C1 $c1, C2 $c2){# alternative, use Interface name
$this->c1 = $c1;
$this->c2 = $c2;
}

public function f(){
# use $this->c1;
# use $this->c2;
}
}

What about static methods ? In a static context, $this is not available.

One first solution occurs in my mind it's passing the instances to all the the static methods. But if there are lots of methods and external dependencies, another solution might be using another static method to get all the instances needed, in order to move all the external dependencies to one method and make easier managing the class. A kind of internal 'Registry' design pattern.

class A {
const INST_c2 = 1;
const INST_C2 = 2;

public static function getInstance($instance){
if ($instance==self::INST_C1){
return c1::GetInstance();
} else if ($instance==self::INST_C2){
return c2::GetInstance();
}
}

public static function f(){
$c1 = self::GetInstance(self::INST_DB);
# use $c1;

$c2 = self::GetInstance(self::INST_C2);
# use $c2;
}

}

Of course there are other solutions, more or less convient depending on the needs.
Any other ideas ?

PHP UK conference 2010 talks

I attended the PHP UK conference 2010 on Friday. Unfortunately the event took place in one day, so there were three talks at each time slot in different rooms. I had to choice the most promising each time. It was a pity to have some very interesting ones at the same time (like AntiPHPatterns and RDBMS, or DB optimisation and the PHP 5.3). Fortunately, I've already found almost all the slides and notes online.
I choose the excellent PHP-strictly-related talks of S.Priebsch, F.Potencier and J.Schlüter as well as the good Seguy's talk about security (and the quite unsatisfying Hudson's talk).
Some interesting comments on joindin.

slides
The lost art of simplicity - Josh Holmes
slides + transcript

RDBMS in the social networks age - Lorenzo Alberton
slides

AntiPHPatterns - Stefan Priebsch
slides

Would you like docs with that? - Stefan Koopmanschap
slides

Database optimisation - Remo Biagioni
not found :(

PHP 5.3 in practice (dependency injection and lambda/closures)- Fabien Potencier
slides

Living with legacy code - Rowan Merewood
slides

PHPillow & CouchDB & PHP - Kore Nordmann
slides

'In search of...' - integrating site search systems - Ian Barber
not found :(

Regex-fu - Juliette Folmer
notes

Best practices in web service design - Lorna Mitchell
slides

Other talks:
Hidden features - from core to PECL - Johannes Schlüter
Cloud computing for PHP using the Windows Azure SDK - Rob Allen
Web and mobile application monetisation models - Chuck Hudson
PHP code audits - Damien Seguy
PHP on the D-BUS - Derick Rethans

Saturday, February 27, 2010

PHP UK 2009 conference - talk slides

I've just searched and found the slides of the online talks made at the PHP conference 2009 that I couldn't attend.
For some of them, a few-line-summary.


The future's so bright, I gotta wear shades (keynote) by Aral Balkan
not found :(

Clouds on the horizon? Get ready for Drizzle by David Axmark
slides
Drizzle, a light faster version of mysql: only UTF8, features as plugin, semplified protocol. BSD licence.

Flex and AIR for PHP programmers by Mihai Corlan
page
Flex is an open source framework to build flash application for developers, without using Authoring tools. It includes teh SDK, an IDE and compilers as well as a rich library.
Basically, the frameworks allows to to write flash applications using HTML+CSS language + embedded OOP scripts, much easier then action script.

Living with Frameworks by Stuart Herbert
slides

Myphp-busters: symfony framework by Stefan Koopmanschap
slides

Of Lambda Functions, Closures and Traits by Sebastian Bergmann
slides

PHP on Windows - the undiscovered country by Hank Janssen
video

Security-Centered Design - exploring the impact of human behavior by Chris Shiflett
slides

Sharding Architectures by David Soria Parra
slides
Master / slave combination pros and cons, table spliting, mysql proxy with LUA

State Machines to State Of The Art: Smart, efficient design using ReST & MVC by Rowan Merewood
slides

What's new in PHP 5.3 by Scott MacVicar
slides

Sunday, February 14, 2010

Upload a tree of files and subdirectory to a remote FTP server

I've recently been asked to move a site (1Gb of files) from a Italian hosting linux (no ssh) to the same cheap hosting but to another server windows (damn ! no ssh, no console commands from PHP, the only way to upload files is the old slow uncool FTP).

Problem: I've got an extremely poor upload bandwith in my house in UK. So, I've used another hosting with SSH (dreamhost, in US) and:
1) got data from the 1st hosting (step1). Uploaded a php files that runs "tar -cf all.tar *"m, executed a "wget" to get the tarball, extracted the tarball.
2) uploaded to the second Italian windows hosting (step2).
ncftpput -R -v -u "username" ftp.site2.it /fpt-root-folder .

Weird tricky situation, isn't it ?

Friday, February 5, 2010

practice tests for zend php 5 certfication

I'm selling
4 exam practice online test for "Zend PHP 5 Certification", GBP 10.

description
http://shop.zend.com/eu/php-certification/zend-php-certification-online-practice-testing.html

contact me at elvisciotti [at] gmail (dot) com, payment through paypal

Thursday, February 4, 2010

PHP and scalability

As PHP is becoming a widely used web server technology, more and more developers are comparing PHP with other technologies like J2EE or .NET.
It has been the butt of criticism as considered not scalable: totally wrong !

A system is scalable when is able to keep the performances under an increased load, mainly due to more users. Speaking about scripting execution velocity (that is a constant in that evaluation) is a completely different kettle of fish.

So, PHP, Python and Perl absolutely scale as J2EE/.NET if the server is upgraded or more parallel servers are added.

Note that all the session-related problems (sticky sessions etc..) are managed in a lower layer, so PHP has no problem with that.


An interesting book about scalability is :Building Scalable Web Sites - written by Cal Henderson, the chief software architect of Flickr (built with PHP)

Saturday, January 30, 2010

Who reads this blog ?

This is the map made by google analytics on this blog.
It's rather foreseeable to see which are the countries more interested in a technical blog.
I'm only surprised to see no visits from China and Norway, as well as same number of visitors from Spain and Ukraine and Romania.



To obtain a better paid job I'm really thinking about moving to Madagascar :D

PHP for file moving / managing

PHP is a technology damned cool for web application but the language doesn't provide an advanced syntax as Python in itself. However, by writing readable and maintenable code (for instance by smartly separating features in function and classes), PHP is satisfying also to make file managing / system scripts, IMHO of course :)

Example
Here is a simple script I'm using to copy the latest mp3 files from a directory to another one (ipod shuffle) skipping the already existing files. Basically it's a kind of one-way-sync script for files filtered by mask and creation date. (To run it from the command line, launch it from the destination directory. e.g.: "php -f script.php" in the root of the ipod, or any USB MP3 player)



define('_SOURCE_PATH_', 'd:/documents/Music/incoming/');
define('_DEST_FOLDER_' , 'Music/'); #ipod shuffle

foreach (new DirectoryIterator(_SOURCE_PATH_) as $f) {

if ( Utils::is_recent_mp3( $f->getPathname() ) &&
Utils::copy_if_not_exists( $f->getPathname(), _DEST_FOLDER_.$f->getFilename() )
)
echo "[COPIED][{$f->getFilename()}]\n";

}




class Utils {

public static function is_recent_mp3($path, $daysOld = 7) {
return ( substr($path,-1)=='3' && filemtime($path) > ( time()-$daysOld*24*3600) );
}

public static function copy_if_not_exists($from, $to){
return ( file_exists($from) && !file_exists($to) ) ? copy($from, $to) : false;
}

}

Tuesday, January 26, 2010

Simple PHP script to edit front end components

I've recently built a very simple web site. The only dynamic requirement was having some parts of the front end editable (WYSIWYG) by an administration area (user and password). Basically, a very simple basic CMS for one user.

Solution
A MySQL database is not needed, saving to files is much more appropriate for these requirements. Also SQLite is not necessary, as we just want to do only basic operations.
To do it, I've used one of my scripts that meets all of those requirements using only one file (the script, to place in any position, better a separate "admin" folder) + a config file (basic options: array with the list of the frontend component and their relative paths, user and password to login) + FCK editor files.

The script (protected with a simple session control + form to login) basically lists the components and allows to click on them and change the text inside using FCK editor (free WYSIWYG html editor). Also a simple backup system is provided, by keeping/restoring the previous version saved.

It's quite easy to implement a script like that.
To whom may be interested in my version (<200 LOC, made long time ago, so PHP4 compliant), let me know.

Wednesday, January 20, 2010

My Zend Certification

Just passed my ZCE PHP5!!



90 tech questions, some of them answerable only by reading some books, some others by knowing the exact behaviour and arguments of PHP5 functions and settings (quite a lot of stuff to remember considering also XML, PDO, STD lib,streams and filters), some other only with work experience, some of them with a code/algorithm comprehension ability and deep OOP skills.

It will may be more useful than my master's degree in my CV :)

Curiosity: how many certified engineer PHP5 are there at the moment in :
Germany: 338, UK: 251, France:222, Italy:53, Spain: 40, Ireland:35
USA:746, India:128, Canada: 114, China: 28


Thursday, January 14, 2010

PDO example


try {
$pdo = new PDO("mysql:host=127.0.0.1;dbname=dev;","root","" );
#$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_WARNING);
$pdo->exec("DELETE FROM `User` WHERE id<>293968 ");

#insert
$insertedRows = $pdo->exec("INSERT INTO `User` (username, password) VALUES ('elvis','ciotti') ");
$lastInsertId = $pdo->lastInsertId();
echo "Inserted $insertedRows rows [id = $lastInsertId]\n";
$pdo->exec("DELETE FROM `User` WHERE id=$lastInsertId ");

#fetch
foreach ($pdo->query("SELECT * FROM `User` ", PDO::FETCH_ASSOC) as $row){
echo "{$row['id']}:{$row['username']}\n";
}

#insert con statement ":"
$stmt = $pdo->prepare("INSERT INTO `User` (username, password) VALUES (:username, :password) ");
$stmt->bindParam(':username',$user);
$stmt->bindParam(':password',$pass);
#
$user='aaaa'; $pass='aa'; $stmt->execute();
$user='bbbb'; $pass='bb'; $stmt->execute();

#insert con statement "?"
$stmt = $pdo->prepare("INSERT INTO `User` (username, password) VALUES (?, ?) ");
$stmt->bindParam(1,$user);
$stmt->bindParam(2,$pass);
#
$user='cccc'; $pass='cc'; $stmt->execute();
$user='dddd'; $pass='dd'; $stmt->execute();

#insert con execute ":"
$stmt = $pdo->prepare("INSERT INTO `User` (username, password) VALUES (:username, :password) ");
$stmt->execute(array(":username"=>"eeee",":password"=>"ee"));

#insert con execute "?"
$stmt = $pdo->prepare("INSERT INTO `User` (username, password) VALUES (?, ?) ");
$stmt->execute(array("ffff","ff"));

#fixed val, no vars
$stmt->bindValue(1,"gggg");
$stmt->bindValue(2,"gg");
$stmt->execute();


$stmpt_all = $pdo->prepare("SELECT * FROM `User` LIMIT 10");
$stmpt_all->execute();
#echo "all: ".print_r($stmpt_all->fetchAll(),1);

$stmpt_all = $pdo->prepare("SELECT id, username, password FROM `User` LIMIT 10");
$stmpt_all->bindColumn(1,$id);
$stmpt_all->bindColumn(2,$user);
$stmpt_all->bindColumn(3,$pass);
$stmpt_all->execute();
echo "fetch: {$stmpt_all->rowCount()} rows: \n";
while($row = $stmpt_all->fetch(PDO::FETCH_BOUND)) { #foreach
echo " [$id][$user][$pass]\n";
}


} catch (PDOException $e){
echo $e->getMessage();
}

?>

Saturday, December 19, 2009

PHP Arrays sort

There are lots of PHP defined function to order arrays (the core of PHP, technically are hashmaps), ordering by value or keys, preserving key order or not, using an user-defined function, normal or reverse order, etc...

Following, some clear example of the main ones, and some tips about how to remember them

ORDER BY VALUE

sort(): order by VALUE (keys destroyed and renumberted starting from zero)
$a = array('z'=>'A', 'y'=>'C','k'=>'B','x'=>'B');
sort( $a ); # Array ( A ,B ,B ,C )

asort(): as the previous, but it maintains index association
$a = array('z'=>'A', 'y'=>'C','k'=>'B','x'=>'B');
asort( $a ); # Array ( [z] => A , [k] => B , [x] => B , [y] => C )

natsort(): use "natural" sorting
$a = array('z'=>'5p', 'y'=>'10p','20p');
sort( $a ); # Array ( 10p ,20p ,5p )
natsort( $a ); # Array ( [2] => 5p , [0] => 10p , [1] => 20
p )

ORDER BY KEY

ksort(): order by key (maintaining associations)
$a = array('z'=>'A', 'y'=>'C','k'=>'B','x'=>'B');
ksort( $a ); # Array ( [k] => B , [x] => B , [y] => C , [z] => A )


USER-DEFINED COMPARISON FUNCTION

usort(): compare using an user-defined function. (keys destroyed and renumbered starting from zero)
$a = array( '0'=>array('id'=>4,'n'=>'aaa') , '1'=>array('id'=>2,'n'=>'bbb'), '2'=>array('id'=>1,'n'=>'ccc'), );
usort($a, function ($a, $b) { #order by '[id]' contained in the elements #closure (php 5.3)
return ($a['id'] < $b['id']) ? -1 : 1; }); #Array ( Array ( [id] => 1 [n] => ccc ) ,Array ( [id] => 2 [n] => bbb ) ,Array ( [id] => 4 [n] => aaa ) )

uasort(): as usort but MAINTAINS the KEYS

HOW TO REMEMBER FUNCTION NAMES

sort = default sort behaviour: order by value and destroy keys
If the function name contains:
u = sort using [U]ser-defined function (Usort, Uasort, Uksort)
a = [A]ssociative: maintains key order (Asort, Arsort, uAsort)
k = order by [K]ey (Ksort, Krsort)
r = [R]everse order (aRsort, kRsort, Rsort)

OTHER ARRAY USEFUL FUNCTIONS

shuffle(): scramble array s contents. (keys destroyed and renumberted starting from 0)

array_rand($array, $number): return $number random elements from $array

array_multisort()

array_shift( array &$array ) ; return the array shifted by 1element off the beginning of array (remove the 1st)

array_slice( array $array , 3, 2, $preserve_keys); RETURNS 2 elements starting from the 4th. if $preserve_keys is true, the keys in the return array are the same in the original one
$a = array(0=>1, 1=>2, 2=>3, 4=>4, 3=>5, 5=>6);
$a = array_slice($a,3,2); #Array ( 4 ,5 )

array_splice(): remove the slice (REFERENCE) and return the removed part
$a = array(1, 2, 3, 4, 5, 6);
$returned = array_splice($a,3,2); #remove 2 elements from 4th elem. return the removed slice
# $returned = Array ( 4 ,5 )
# $a = Array ( 1 ,2 , 3 , 6 )

Thursday, December 10, 2009

Netbeans 6.8

Netbeans 6.8 is now available !
New features:
  • Symfony support (integrated prompt, syntax + help for command line code generator, shortucts) + YAML syntax support
  • better code completion, supporting PHP 5.3 features (namespaces)
  • PHPUnit improvements
  • PHP application from remote servers
  • SQL better auto completition
  • Embedded Browser + Web Preview for HTML and CSS

Thursday, November 26, 2009

Checking PHP script performance with Xdebug

Xdebug [http://www.xdebug.org/] is a useful tool to debug PHP scripts. An interesting feature is the script profiling.

If the option is enabled, Xdebug will be able to trace and save information (time, details) about all the functions/methods called in the script (CLI or Apache).

The aim of the profiling is mainly recognizing bottlenecks or simply what parts of the code that are slow.

In order to analyze the log file created, use KCacheGrind or WinCacheGrind (see screenshots below).

Setup and docs at [http://www.xdebug.org/docs/profiler].

Configuration for Wamp (PHP 5.3)

#php.ini
[xdebug]
zend_extension=c:/wamp/bin/php/php5.3.0/ext/php_xdebug-2.0.5-5.3-vc6.dll
xdebug.profiler_enable = 1
xdebug.profiler_output_dir=C:/wamp/www/profile/
xdebug.remote_enable=on
xdebug.remote_handler=dbgp
xdebug.remote_host=localhost
xdebug.remote_port=9000
xdebug.remote_mode=req

Screenshots


Thursday, November 19, 2009

Profiling MySQL

To analyze the db server usage in a complex PHP application, the first step is to profile the db server.
There are lots of tools to profile, but I think it's very easy to make a customized code to save the data really needed.
The idea is save information about some queries in the production environment (about 1% of the queries is usually enough, depending on the traffic).


MySQL profiling

Hoping there is a class used to manage queries (or at least mysqli class), it doesn't take long to replace a function that manages the queries with something similar to the following code (written in a simple way to show the idea):


class DB extends mysqli {
...
function query ($q) {

$start = microtime(1);
$this->query($q);
$wtime = microtime(1) - $start;
#save 1% of the queries + info
if ( rand(0,100)<1>query("INSERT DELAYED INTO `ProfileData` (q,wtime,created,...) ($q,$wtime, NOW(), ...) ");
}

}
...
}


What other info to save ? some ideas:
  • client IP
  • other $_SERVER info: user-agent, request_method, etc...
  • PHP backtrace (to understand which line launched the query)
  • web server load
  • mysql server load
  • ...
How to analyze results making queries on the `ProfileData` table.
example: queries grouping by query and showing the average time of the queries. In this way, you can find what queries are the slowest ones.



-- select the slowest queries (average time) in the last 24 h
-- exclusion of the queries executed only once to exclude missing sql cache
SELECT `q`,AVG(`wtime) as "medium time", COUNT(`id`) as "occurences"
FROM `ProfileData`
WHERE `created` > DATE_ADD(NOW(), INTERVAL -1 DAY)
GROUP BY `q`
HAVING COUNT(`id`) > 2
ORDER BY AVG(`wtime) DESC
 

PHP and tips|PHP