Wednesday, March 23, 2011

PHP singleton inheritance

Prior to PHP 5.3, here is how we implement singleton:
class Service
{
private static $_instance = null;
private function __construct(){};
private function __clone(){};

public static function getInstance()
{
if (self::$_instance === null) {
self::$_instance = new self;
}
return self::$_instance;
}
}

However, we all know that it is very tricky if we want to extend/inherit this singleton class.
PHP 5.3 introduces LSB, which stands for Late Static Binding. It solves our problem of inheriting a singleton class. In PHP 5.3, we implement singleton in this way
class Service
{
private static $_instance = null;
private function __construct(){};
private function __clone(){};

public static function getInstance()
{
if (static::$_instance === null) {
static::$_instance = new static;
}
return static::$_instance;
}
}

Simply replace the 'self' keyword with 'static', we can inherit a singleton just like usual inheritance.

The difference is self keyword is bound to the referenced property or method at compile time. The self keyword points to the containing class and is unaware of subclasses. The static keyword forces PHP to bind to the code implementation at the latest possible moment.

how to use left join in mysql

Let's setup two tables for our experiment.

create table student(id int primary key auto_increment, name varchar(255));

insert into student (name) values('henry'),('jack'),('alice');

create table class_a(id int primary key auto_increment, student_id int, registered_datetime datetime);

insert into class_a(student_id, registered_datetime) values(1,now());


We use a simple left join to see the result:


select s.*,c.id as class_id from student s left join class_a c on s.id = c.student_id;
+----+-------+----------+
| id | name | class_id |
+----+-------+----------+
| 1 | henry | 1 |
| 2 | jack | NULL |
| 3 | alice | NULL |
+----+-------+----------+


We can see that left join returns all rows from the left table(student) even the student may not have a match in the right table(class_a). In this case, any c

So thing are quite obvious now. If we only want to get the students that are not registered in class_a, we can simply add a filter for left join:

select s.*,c.id as class_id from student s left join class_a c on s.id = c.student_id where c.id is null;
+----+-------+----------+
| id | name | class_id |
+----+-------+----------+
| 2 | jack | NULL |
| 3 | alice | NULL |
+----+-------+----------+

Tuesday, March 22, 2011

phpundercontrol build success even with php codesniffer violation error

This issue had been confusing me for a while, cause it seems phpundercontrol will build fail only when phpunit failed.

Later i check the difference in the build.xml between PHPUnit target and CodeSniffer target. I found PHPUnit is setup like this '' while codesniffer doesn't have 'failonerror="on"', after i add it to codesniffer target, phpundercontrol will build fail if there is any codesniffer violation.

Friday, March 18, 2011

VIM IDE for PHP

1. install the project plugin for VIM. Here is the link: http://www.vim.org/scripts/script.php?script_id=69

2.
sudo aptitude install exuberant-ctags
cd ~
wget http://rafal.zelazko.info/wp-content/uploads/ftp/vim-custom.tgz
tar -xvzf vim-custom.tgz -C ~

Link for step 2: The link: http://rafal.zelazko.info/2010/04/18/vim-php-symfony/

Tuesday, March 15, 2011

install mongodb php driver on windows

Download the correct driver for your environment from http://github.com/mongodb/mongo-php-driver/downloads. For my case, i download "mongo-1.1.4.zip — All of the Windows build for the 1.1.4 release"

Unzip the package. There are several entries, for example:

mongo-1.1.4-php5.2vc6
mongo-1.1.4-php5.2vc6ts
...

Based on the official document, vc6 is for Apache (vc9 is for IIS). 'ts' means Thread Save. Thread safe is for running PHP as an Apache module (typical installation), non-thread safe is for CGI.

So i copy the mongo.dll from the mongo-1.1.4-php5.2vc6ts folder to my php/ext/ folder. And then update my php.ini by adding extension=php_mongo.dll

Finally, restart my apache and then have a look at phpinfo(), i can find a mongo section. It is done

Monday, March 14, 2011

PHP case insensitive file_exists

We know that PHP's file_exists is case sensitive on *nix system. However, i've been through a situation that i need this function case insensitive. For example, there exists a file: /var/www/project/public/images/company/logo.png. In Url it will be http://project.com/images/company/logo.png. Now, if the html code is < img src = "http://project.com/images/Company/logo.PNG" > or even < img src = "images/Company/Logo.png" >, it works fine on windows. But on linux, it won't work. My task is, i need to allow users to export some special html pages in a zip archive so that they can browse them offline. If the html pages contain image links, the images will be exported too if they exists. Well, as you can imagine, it is pretty much like the "Save as..." function when you right click your mouse on a web page.

I can't find a perfect solution. Some solutions only allow you to have file name case insensitive, and you still have to ensure the directory name of the file must be correct in case sensitive way. Some solutions use customized glob() functions that i can't easily understand. So i finally decided to implement my own solution based on my situation.

Here is my thought: some specific path is defined in your config file and you can never get it wrong. For example, you may have config settings like this:
//paths
$conf['root_dir'] = dirname(__FILE__) . '/..';
$conf['public'] = $conf['root_dir'] . '/public';
$conf['images'] = $conf['public'] . '/images';
So, the only uncertain part is the sub folders and files under the 'images' folder. Here is how i implement my case insensitive file_exists():
//$filename is the full path file name, like /var/www/project/public/images/Company/Logo.PNG
//$baseDir is the base directory that you can't get it wrong, here it might be /var/www/project/public/images/
//return: the function return false if file NOT exists,
//it will return the correct case sensitive path if the file exists in case insensitive way.

function caseInsensitiveFileExists($filename, $baseDir)
{
//well if file_exists() can find the $filename, we can return
if(file_exists($filename) {
return $filename;
}
//we only do this on *nix system, on windows, we don't have to worry about case sensitive issue.
if (strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
$iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($baseDir));
foreach ($iterator as $value) {
if ($value->isFile()) {
$filePath = $value->getPathname();
//if they are equals, we know the $filename exists.
if (strotolower(filePath) == strtolower($filename)) {
return filePath;
}
}
}
}
return false;
}


How is this function's performance if we have huge number of files and folders under $baseDir? I haven't really tested this issue yet. At the moment this function serves my purpose very well. However, i'm looking forward to any other decent implementation.

Thursday, March 10, 2011

a difference i didn't expect between php 5.2 & php 5.3 (overriding abstract function)

Here is my code:

abstract class App_Daos_Abstract
{
abstract public function buildModel($result);
}

class UserDao extends App_Daos_Abstract
{
public function buildModel($result = null)
{
}
}

If i run this code on php 5.2.14 + windows, i will get "Fatal error: Declaration of news::buildModel() must be compatible with that of App_Daos_Abstract::buildModel()".

However, if i run the code on php 5.3 + ubuntu, everything is fine.

I don't think windows or ubuntu matter. I think this is a difference between PHP 5.2 and PHP 5.3. So even at this point PHP 5.3 is more closer to JAVA.