I have to say, for someone being a blogger since 2005, it feels tremendously awkward to write a Hello World post in 2022.
Truth to be told, it’s been a while, literally years since I last posted something to this (English) blog. It meant to be used for advanced, programmers topics, because writing specific advanced technical topic to small Serbo-Croatian speaking readers felt like … well not like talking to the walls, but let’s say talking to really small bunch of people, part of local dev communities. So I decided, I’ll keep it separate, posting engineers topic to EN for broader public, and everything else to SR blog. Most of my fellow Serbian devs speak perfect English anyway. And it was fine.
But then it came 2017, I’ve moved to Germany and all of sudden had plenty of material for my Serbian (non) IT friends. How’s in Germany, how to find a job, how much are taxes, why the hell are rents so crazy expensive in Munich etc. And the good old Serbian blog was fully back in business.
But it’s been 5 years since then, and I think I’m done. Nothing more to say, nothing left that wouldn’t include politics, pollution, god know which reason why we left, and reopening that book would just … hurt.
So I thought, let’s start blogging again and let’s start fresh new. Because irony is, when I moved to Munich, I met plenty of new people and some of them I convinced to start blogging, while for some of them were already doing it, I successfully convinced them that Medium is not the right place to be. The right place is that fuzzy little warm page with domain name you picked on whatever tech stack you want, where you have everything, just everything under control!
So clean plate was initial idea – get rid of everything and start fresh new! But then I saw, I can’t just remove all those prehistoric posts. Maybe they are from 2008, maybe they are useless these days, but hey, they are part of me, an old chap trying to stay on top of everything in his late 40’s.
So damn. Let’s roll the damn thing over again, put shiny new things on the top and see how it’s gonna be.
* Traffic lights taken from my first website iteration in 2003, thank you Web Archive!
It’s been a while since I last updated my Curl HTTP Client class. That’s the class that we’ve been using for years now, for all kinds of site scrapping, bulk domain registration without API, … and even today we use it as a part of core in our brand new Payment system.
Since I had some spare time this weekend, I finally managed to merge some of updates we’ve created during all these years and put a class to github so I can do frequent updates regularly. Don’t worry, class has retained most of it’s previous functionality explained here so update to latest version shouldn’t cause any problem.
When I started writing this post I wasn’t sure should I put this into programming category or fun … I mean, validating if passed variable is integer aka whole number, how hard can it be? It appears not really easy in PHP 🙂
First off some background, I needed to validate an array with db key values (like array(1,2,6,7,…n)), so I thought of using simple function like array_filter with callback, something like:
array_filter($foo_array, 'is_int');
where is_int is callback, calling built in is_int function for each array value in order to filter out non int values.
The problem is (yes after 10 years dealing with PHP I am aware of that), PHP doesn’t treat int and string numbers the same, so string ’42’ wouldn’t be recognized as integer.
is_int('42'); //false
is_int(42); //true
To make things more “interesting” for programmers, if you have integer form data like age, year or whatever, they will be sent trough $_POST/$_GET/$_REQUEST arrays as ‘string numbers’ (so string ’42’ not int 42).
There is nice function to deal with such things and it’s name is is_numeric … but it only checks if string is actually number, so float values will be evaluated to true as well. ctype_digit on the other hand is opposite of is_int, it will only return true if test variable is string number, so ’42’ would evaluate to true, but 42 to false.
ctype_digit('42'); //true
ctype_digit(42);//false
And to make things even worse, PHP is silently converting really big integers to float (those bigger than PHP_INT_MAX const) so guess what would you get for number like is_int(23234234234235334234234)? Yep, false 🙂
Yeah I know, you could cast var to int and do is_int … or cast var to string and do ctype_digit … and other dirty hacks… but what if someone smart from PHP team had decided to let say add 2nd argument to is_int check so you can check for type in some kind of ‘non strict’ mode, so string ’42’ is actually evaluated as integer? Something like this in C I guess:
function is_int(int var, int strict = 1)
{
//if strict is false evaluate string integers like '42' to true!
}
All in all (at least to me), the easiest way to validate whether a variable is whole number (aka string or integer string) is with regular expression. Something like this:
/**
* Test if number is integer, including string integers
* @param mixed var
* @return boolean
*/
function isWholeNumber($var)
{
if(preg_match('/^\d+$/', $var))
{
return true;
}
else
{
return false;
}
}
Someone from PHP dev team should really consider fixing this.
Today I had to deal with one huge table and cleanup all data where foreign key doesn’t have it’s primary key match in original table, just to remind myself how sub-queries in MySQL are terrible slower than joins.
I have some script which generates domains from typos, so I have one table with original domains (master_domains) and other one (result_domains) with generated typo domains. Basically something like this:
mysql> describe master_domains;
+--------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+--------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| domain | varchar(255) | NO | UNI | NULL | |
+--------+------------------+------+-----+---------+----------------+
2 rows in set (0.07 sec)
mysql> describe result_domains;
+-----------+------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------+------------------+------+-----+---------+----------------+
| id | int(10) unsigned | NO | PRI | NULL | auto_increment |
| domain | varchar(255) | NO | UNI | NULL | |
| master_id | int(10) unsigned | YES | MUL | NULL | |
+-----------+------------------+------+-----+---------+----------------+
3 rows in set (0.01 sec)
Table result_domains has master_id which is foreign key reference to primary key (id) in master_domains table. Since I also have other scripts generating domains without typos (which store result_domains.master_id field as NULL), today I simple wanted to get rid of those masters without proper master_id reference in result table or in other words those master domains where result_domains.master_id is NOT NULL.
With sub-queries you could write query easily with something like this:
delete from master_domains where id not in
(select master_id from result_domains_frontend)
It is good habit to always run select query before deleting big number of rows (just to make sure your query is written correctly) so I tried select query first:
select * from master_domains where id not in
(select master_id from result_domains_frontend) limit 10
However, it took several minutes to run without any output so eventually I’ve decided to stop it. I know that sub-queries are much slower than joins, so decided to do try removal operation with left join.
Left joins are actually perfect weapon to find rows that exist in one (left) and doesn’t exist in other (right) table. They also have one big advantage over sub-queries – they are performing much faster, plus they are backward compatible with old prehistoric MySQL 5.x versions. However delete syntax is little bit tricky so after few trial and errors eventually I came out with this query:
delete master_domains.* from master_domains
left join result_domains_frontend
on master_domains.id=result_domains_frontend.master_id
where result_domains_frontend.master_id is null ;
And voila after a while it came up with result:
mysql> delete master_domains.* from master_domains
left join result_domains_frontend
on master_domains.id=result_domains_frontend.master_id
where result_domains_frontend.master_id is null ;
Query OK, 270558 rows affected (46.58 sec)
mysql>
To move one table from one db to another, you can create new table (create table foo_new like foo) in db where you want to move table and then copy data with insert into/select query. However there is much easier way which is especially handy when you deal with big tables.
As you probably aready know, there is easy way to rename MySQL table just by issuing rename clause in alter statement:
ALTER TABLE foo RENAME TO new_foo;
You can also use RENAME TABLE syntax like this:
RENAME TABLE foo TO new_foo;
Now, when you need to move table from one db to another, all you have to do is to specify it’s current db and new db name as table prefix. For example if you want to move table foo from current db to new db you can issue queries like these:
ALTER TABLE currentdb.foo RENAME TO newdb.foo;
or
RENAME TABLE currentdb.foo TO newdb.foo;
Btw there is important difference between ALTER and RENAME statements in a way that with RENAME you can rename more than one tables at once. This comes handy if you want for example to swap names of two tables:
RENAME TABLE table1 TO temp, table2 TO table1, temp TO table2;
Recently I got brand new HTC Hero – great android based phone. Since my previous phone (Nokia N73) has been working with Mac without any problem I was very disappointed to figure out that I have to deal with Windows for syncing my phone with computer and firmware upgrades.
After I upgraded it to latest official 2.73.405.4 ROM, I used Google Contacts/Calendar apps to sync my previous Nokia 73 stuff with Google and Hero, so having laptop<-->mobile connection to Internet (tethering) really sounded like something possible to achieve. A friend of mine with HTC Magic told me about way to connect to Internet with Wifi Tether application, which works on root-ed devices only. So after I passed trough complete rooting procedure explained here and here, I gained root access but still wasn’t able to make Wifi Tether work with Mac. Hero was visible as another AP, and even thought Mac was actually able to connect to it, I never got “outside” access to the Internet and eventually gave up. I found some threads that modaco custom ROM might be solution but figured that for newbie in android world like me, chances to brick brand new device while doing unsupported ROM upgrade are not so low so eventually I gave up.
Unlike for wifi tethering, USB tether for Hero and Windows comes “Out of the Box” (all you have to do is to turn on mobile sharing) but unfortunately it doesn’t work with a Mac. When you connect Hero to Mac, instead of new network device Mac see it as modem, but if you try to dial (like with *99#) you obviously get an error.
After I spent several hours reading endless discussions on various forums, today I finally managed to connect my MacBook Pro on the Internet with my HTC Hero mobile Internet (EDGE/GPRS/3G/HSDPA) connection.
Before I delve into instructions, please bear in mind that although this tutorial is based on HTC Hero and Mac running on latest (10.6.1) Snow Leopard, as far as I can tell it should be working with any other Android device or older version of Mac. I assume that you have MacPorts installed and that you are able to connect to Internet with your Mobile Phone.
Prepare your phone
————————–
You are going to install azilink on your phone. Since all tether applications are removed from Android Market, you have to download it directly from site. But before you do that, you have to make sure that installing applications from unknown sources is allowed. So Press Home, then Menu->Settings->Applications and make sure that “Unknown Sources” is checked. Also in Development menu make sure that “USB Debugging” is checked.
Now on your phone open browser and go to http://azilink.googlecode.com/files/azilink-2.0.2.apk , download file and follow install instructions. Once azilink application is installed start it and make sure that “Service Active” option is checked.
Prepare your Mac
————————–
Step1: TuneTap App
Download and install tuntap for Mac OS X (http://tuntaposx.sourceforge.net/) on the Mac and restart your mac.
Step2: Android SDK
Download Android SDK (http://developer.android.com/sdk/index.html) for Mac and unpack it somewhere on your machine. I used my $HOME dir (/Users/dinke) so I unpacked whole folder and named it android-sdk so full path is /Users/dinke/android-sdk. Since you are going to call tools from that folder, we have to put it into our $PATH variable by editing $HOME/.bash_profile file. I assume that you don’t have UNIX experience so this is step by step guide :
1) Open Terminal Applications
2) Type:
cd
and hit enter
3) You are now in your home dir (ie. /Users/dinke). Now you are going to edit .bash_profile file with pico editor :
Type:
pico .bash_profile
4) Add this line to last line of file:
export PATH=/Users/dinke/android-sdk/tools:$PATH
(replace /Users/dinke/android-sdk/tools with actuall path on your system)
5) Hit ctrl-x then answer Y and hit enter
Now you should be ready to call android tools (like we are going to do later) without specifying full system path.
Step3: OpenVPN2 App
Download and install openVPN2 . We will use MacPort’s port command for doing that. So again open terminal application and type:
sudo port install openvpn2
Now application will be automatically downloaded and compiled. This will take a while, and if this end without any error message you are good to go further 🙂
Step 4: azilink.ovpn file
1) Download http://azilink.googlecode.com/files/azilink.ovpn file
2) Create folder openvpn in $HOME/library folder (so you have new folder in for example /Users/dinke/Library/openvpn
3) Edit file azilink.ovpn and comment out line 8 with TCP_NODELAY (so it may looks like this):
dev tun
remote 127.0.0.1 41927 tcp-client
proto tcp-client
ifconfig 192.168.56.2 192.168.56.1
route 0.0.0.0 128.0.0.0
route 128.0.0.0 128.0.0.0
#socket-flags TCP_NODELAY
#keepalive 10 30
ping 10
dhcp-option DNS 192.168.56.1
4) Save file in new created in new created openvpn folder
Step 5: Modem script
1) Download script from http://pastie.org/405289 (there is download link on top right) and save it somewhere on your system. I assume you saved it under our home dir as modem.sh (/Users/dinke/modem.sh)
2) Give that script executable privileges. So open terminal application and type this:
chmod 777 /Users/dinke/modem.sh
(change path and script name according to your system)
Now we are almost done and we are ready to test actual connection. So connect your phone with Mac with USB cable, open terminal app and type this:
adb devices
You should get something like this:
dragan-dinics-macbook-pro:tools dinke$ adb devices
* daemon not running. starting it now *
* daemon started successfully *
List of devices attached
HT9FSL901734 device
dragan-dinics-macbook-pro:tools dinke$
If you get error (like command not found) check path setting for android sdk tools. If your device is not listed check that it is connected properly. If everything looks ok (you get device id listed) then we can connect our phone to Internet and run actual connection script. Make sure that your phone is connected to Mobile Internet (go to Menu->Settings->Wireless Controll and check Mobile Network checkbox), and then assuming that you’ve saved modem script under /Users/dinke/modem.sh you can run it by typing absolute path in terminal:
/Users/dinke/modem.sh
and you should get output like this:
dragan-dinics-macbook-pro:~ dinke$ /Users/dinke/modem.sh
Tue Nov 10 03:33:53 2009 OpenVPN 2.0.9 i686-apple-darwin10.0.0 [SSL] [LZO] built on Nov 9 2009
Tue Nov 10 03:33:53 2009 IMPORTANT: OpenVPN's default port number is now 1194, based on an official port number assignment by IANA. OpenVPN 2.0-beta16 and earlier used 5000 as the default port.
Tue Nov 10 03:33:53 2009 ******* WARNING *******: all encryption and authentication features disabled -- all data will be tunnelled as cleartext
Tue Nov 10 03:33:53 2009 gw 0.0.0.0
Tue Nov 10 03:33:53 2009 TUN/TAP device /dev/tun0 opened
Tue Nov 10 03:33:53 2009 /sbin/ifconfig tun0 delete
ifconfig: ioctl (SIOCDIFADDR): Can't assign requested address
Tue Nov 10 03:33:53 2009 NOTE: Tried to delete pre-existing tun/tap instance -- No Problem if failure
Tue Nov 10 03:33:53 2009 /sbin/ifconfig tun0 192.168.56.2 192.168.56.1 mtu 1500 netmask 255.255.255.255 up
Tue Nov 10 03:33:53 2009 ./modem.sh up tun0 1500 1502 192.168.56.2 192.168.56.1 init
add net 0.0.0.0: gateway 192.168.56.1
add net 128.0.0.0: gateway 192.168.56.1
Tue Nov 10 03:33:53 2009 Attempting to establish TCP connection with 127.0.0.1:41927
Tue Nov 10 03:33:53 2009 TCP connection established with 127.0.0.1:41927
Tue Nov 10 03:33:53 2009 TCPv4_CLIENT link local: [undef]
Tue Nov 10 03:33:53 2009 TCPv4_CLIENT link remote: 127.0.0.1:41927
Tue Nov 10 03:34:03 2009 Peer Connection Initiated with 127.0.0.1:41927
Tue Nov 10 03:34:03 2009 Initialization Sequence Completed
If you get some errors make sure that you’ve passed correctly trough all needed steps. If no errors found, it is good time to test your new internet connection. You can do so by trying to ping some site or simple opening browser and visiting some Web Site. It should be working just fine!
Speedtest of my HSDPA connection with Telenor Serbia
Very often we need to sort some data by specific field in db table but in a way that NULL values goes at the end of dataset. Typical example is frontend which displays data from specific table, with sortable links at the top where you can make asc/desc sorting simple with one click of the mouse.
Since I am mostly dealing with domains, I’ve decided to create one MySQL table with few domains, simple enough to show solution for this problem.
So problem is, I want to sort data by expire_data field but in a way that NULL field (ie domain which is not regged yet or has expired) always goes at the end. By default NULL fields goes on the top if we sort by acceding (asc) order or at the end if we sort in descending (desc) order.
mysql> select * from domains
order by expire_date asc;
+----+-------------------+-------------+
| id | domain | expire_date |
+----+-------------------+-------------+
| 5 | unexistant.com | NULL |
| 4 | maestrodesert.com | 2009-09-11 |
| 2 | lampix.net | 2009-12-26 |
| 1 | dinke.net | 2010-01-17 |
| 3 | blogodak.com | 2010-09-08 |
+----+-------------------+-------------+
5 rows in set (0.00 sec)
mysql> select * from domains
order by expire_date desc;
+----+-------------------+-------------+
| id | domain | expire_date |
+----+-------------------+-------------+
| 3 | blogodak.com | 2010-09-08 |
| 1 | dinke.net | 2010-01-17 |
| 2 | lampix.net | 2009-12-26 |
| 4 | maestrodesert.com | 2009-09-11 |
| 5 | unexistant.com | NULL |
+----+-------------------+-------------+
5 rows in set (0.00 sec)
We are going to solve this problem by using MySQL IF function, and solution is:
mysql> select * from domains
order by if(expire_date is null, 1, 0), expire_date asc;
+----+-------------------+-------------+
| id | domain | expire_date |
+----+-------------------+-------------+
| 4 | maestrodesert.com | 2009-09-11 |
| 2 | lampix.net | 2009-12-26 |
| 1 | dinke.net | 2010-01-17 |
| 3 | blogodak.com | 2010-09-08 |
| 5 | unexistant.com | NULL |
+----+-------------------+-------------+
5 rows in set (0.00 sec)
MySQL IF function is similar as ternary operator, it returns value of first argument in case when expression evaluate to true, otherwise it returns value of 2nd argument. So in this particular example it returns 1 for NULL values and 0 for the rest, allowing us to have NULL values at the end of the list.
I know that this might sound little bit confusing so we have to go one step further and add another one field in our MySQL table in order to explain what is exactly going on here.
Tuesday, cloudy day in Miami, not really good weather for the beach, but who cares. Today is FOWA day!
Check in was within 08-09AM in beautiful Adrienne Arsht arena. Checked location on Google maps, it’s just nearby my hotel so no need to deal with car. Arrived just few minutes before 09AM, so after they checked my data they gave me blank pass and pen to write down my name/company on it. As every proud Serb I took the chance to draw Serbian flag there so my geek colleagues knows exactly from where I am 🙂
Inside of hall there was bunch of geeks from all colors and ages … but most of them have one thing in common. They were all armed with a Macbook. I counted like 50 Macbook (Pro) laptops, with only one sad PC guy. I joined the mass with my Macbook Pro and started with some kind of live broadcasting to well known Serbian Development Forum.
Before he started his intro speech, Ryan Carson asked from us to meet and shake hands with each others. Most of us were doing that … “Hey bro, how yo doin’ …” and suddenly robots becomes a man. Well done Ryan.
First guy on the stage was Jason Fried who were talking about their Getting Real philosophy, without much noise and any presentation screen behind. He mentioned plenty of good advices regarding productivity, sales, future prediction etc. Jason complained about giving away software for free, because food is not free, our cloth is not free, our car is not free … so why in the world software you made should be free?
After Jason Ajaxian guys (Dion Almaer from Google and Ben Galbraith from Mozilla) took the stage. Their speech was much more interesting to me, with plenty of effective screens behind, describing what is going to happen with browsers in the near future. In one word – revolution, which is going to get current Ajax based applications even more usable with usability closer with those that we have on OS X (they used Mac examples frequently).
After Ajaxian guys, Dan Theurer from Yahoo took the scene. Unfortunately his presentation file was corrupted so somehow he did his speech too fast. Also without presentation slides behind it was really hard to track his speech so many developers took the chance to play with wireless and at the end it seamed that Dan couldn’t wait to move away from the stage which was kind of shame.
After the morning break there was probably the most effective talk made by Joe Stump, lead developer of Digg-a.
Joe used ingenious slides with his and his brother pics from their childhood in attempt to present developers as lazy, moody and egocentric guys (come on, we all know that it is completely the true), and how to make compact and productive team from them.
My favorite quotes:
Developers are EXTREMELY lazy.
Jedi are rare guys
(finding senior programmers is not easy – demonstrated by picture of kid with light Jedi like sward in hand).
Kristine Halvorson, related to Web Content. Although I don’t think many guys from audience found her speech really interesting (I don’t think developers really care about content), her speech was really original and effective. Kristine also had problems with her presentation, but unlike Yahoo guy she didn’t want to continue till backed guys didn’t fix the problem (meanwhile she made them look really funny). After her speech Kristine asked audience why do we have so little females in hall, which was introduction to their talk about that “issue”.
After they ended Aza Raskin from Mozilla took the stage to tell us about all those great little things Mozilla Lab is preparing for us. He was talking about Ubiquity, kind of Firefox add on which would allow you to do many things, like changing content on pages you’re visiting often (like you could easily replace Google logo with your own ad), and many other things. Unfortunately backed guys screwed it again so Aza also stayed without his presentation and had to leave the stage and finish it at the end of show.
After lunch break Joel Spolsky made an interesting and funny talk, where he talked about programmer’s efficiency, setting working environment, office stuff etc. Like Jason he also mentioned interruption as one of the biggest enemies of programmer’s productivity. He claim (and I totally agree) that every developer during his working day usually has about 2 or 3 hours of “total focus” in which time he is 100% focused on problems he is solving. During that period developer usually don’t feel a time (2 or 3 hours pass like a snap). Noisy environment, phone ringing, even going to toilet are the worst enemies of every programmer. That’s why big companies that are paying attention to those stuff (like Google) are trying to keep developer’s focus as long as possible with ie. keeping his snack near by, the same with toilet and even shower booth 🙂
After Joel, some very effective (but personally not so interesting) talks was made by Dave McClure and Alex Hunter from Virgin. And after pause there was another one “talk show” with Joel, Jason and Caron, after which Francisco Tolmasky from company 280 North took the stage.
Francisco made great workshop with Cappuccino and Atlas tool. By using Atlas – kind of point and click tool started from the browser on local host, he used point and click interface to create an feed reader application in like 3 minutes! After that he did the same for iPhone platform. I liked whole thing except the fact that you don’t have ability to do kind of “synchronization” between iPhone and Web project (things are kept in separate files). I even took a chance to talk with Francisco after the show about that, who was BTW the only speaker I had a chance to meet personally.
At the end there was Gary Vaynerchuk’s talk who somehow acted like a Eminem, he talked loud and fast, sometimes cursing, screaming … I could say almost crying 🙂 Don’t have time to repeat here everything Gary said, so if you have a time, here’s video 🙂
At the end we were invited to visit the party on Nikki Beach which as far as I can tell many developers did. Free beer provided by Microsoft … you could hardly find something more attractive 🙂
P.S. This is English translation of FOWA Conference report made originally in Serbian. Now when I got back to my sucky homeland, I managed to translate it completely. Hopefully you enjoyed.
Recently, I had to change default behavior of storing session data into files and use MySQL DB instead. In practice, that means writing whole bunch of callback functions and setting callbacks with session_set_save_handler function. Since I use OOP, what really bothered me was the fact that (according to my PHP CHM Manual sitting on my desktop) for session_set_save_handler, all functions has to exist in global scope, since all callback arguments are strings?
Doing that in non OOP way with 6 functions on global scope is not something I really liked, so I googled for solution and found that you can easily assign an array like array(‘class_name’, ‘method’) for all callbacks in PHP. Cool stuff which allows you to create session handler class with bunch of static methods for those callbacks, but why the hell that is not documented in PHP Manual???
Obviously, since last time I browsed online manual, a lot of thing has changed, one among them is introducing “callback” type in those “pseudo types” used only for documentation purposes. And there, manual for callback says following:
callback
Some functions like call_user_func() or usort() accept user defined callback functions as a parameter. Callback functions can not only be simple functions but also object methods including static class methods.
A method of an instantiated object is passed as an array containing an object as the element with index 0 and a method name as the element with index 1.
Static class methods can also be passed without instantiating an object of that class by passing the class name instead of an object as the element with index 0.
which basically allows you to pass an array with class name and method as callback, and that method will be called.
Let me give you and example with sessions:
<?php
/**
* Sessin_Handlers class
* contains dummy methods needed for session stuff
* Replace content with some real stuff like db conn etc.
*
*/
class Session_Handlers
{
function open($save_path, $session_name)
{
echo "Open Method Called<br>";
return true;
}
function close()
{
echo "Close Method Called<br>";
return true;
}
function read($id)
{
echo "Read Method Called<br>";
return true;
}
function write($id, $sess_data)
{
echo "Write Method Called<br>";
return true;
}
function destroy($id)
{
echo "Destroy Method Called<br>";
return true;
}
function gc($maxlifetime)
{
echo "GC Method Called<br>";
return true;
}
}
//call all method from Session_Handlers statically
session_set_save_handler(array('Session_Handlers', 'open'), array('Session_Handlers', 'close'), array('Session_Handlers', 'read'), array('Session_Handlers', 'write'), array('Session_Handlers', 'destroy'), array('Session_Handlers', 'gc'));
session_start();
// proceed to use sessions normally
?>
As you see, we’ve created simple methods which only echo when they are called (in real life, you should either save session data into file or db). As you can see, we simple passed arrays to session_set_save_handler, which served us to connect class methods with session callbacks.
Although with release of PHP5 we finaly got some long awaited OOP features, sometimes I really miss overloading capability which exists in languages like Java. I am talking about something like this:
class Overloading_Test
{
public void hello()
{
System.out.println("Hello Anonymous");
}
public void hello(String name)
{
System.out.println("Hello " + name);
}
public void hello(String firstName, String lastName)
{
System.out.println("Hello " + firstName + " " + lastName);
}
}
This way you can call either hello with no arguments at all, or with one or two arguments, and proper method would always be called. Unfortunately, if you try something like this in PHP, it would give you fatal error, because basically, methods cannot be redeclared, since support for overloading is not part of core language like in Java.
However, there is still a way to achieve this Java like overloading functionality by using “magic” methods that are described in PHP Manual. Although it is not clear from manual how could you achieve exact functionality like in Java, I played a little bit with __call function, and get interesting workaround.
<?php
class Overloading_Test
{
function __call($method_name, $arguments)
{
//list of supported methods
//only 'hello' for this test
$accepted_methods = array("hello");
//in case of unexistant method we trigger fatal error
if(!in_array($method_name, $accepted_methods))
{
trigger_error("Method <strong>$method_name</strong> doesn't exist", E_USER_ERROR);
}
//we inspect number of arguments
if(count($arguments) == 0)
{
$this->hello1();
}
elseif(count($arguments) == 1)
{
$this->hello2($arguments[0]);
}
elseif(count($arguments) == 2)
{
$this->hello3($arguments[0], $arguments[1]);
}
else
{
return false;
}
}
function hello1()
{
echo "Hello Anonymous<br>";
}
function hello2($name)
{
echo "Hello $name<br>";
}
function hello3($first_name, $last_name)
{
echo "Hello $first_name, $last_name<br>";
}
}
$ot = new Overloading_Test();
$ot->hello();
$ot->hello("John");
$ot->hello("John", "Smith");
//this one will produce fatal error
//$ot->test();
?>
If you run this code, you will get something like:
Hello Anonymous
Hello John
Hello John, Smith
So, what is going on here? Whenever we call some undeclared method (which is the case with ‘hello’ method here), magic method __call is called, and two arguments (method name and arguments) are passed to it. For this simple test, we only support overloading of ‘hello’ method, so in case you try any other, we trigger fatal error.
What’s going on further is, we simple check number of argumens passed (by counting $arguments array), and call proper method. For the sake of clarity, I only used simple overloading based on number of arguments, but you could also check for argument type (ie string, integer etc.) and call proper method.
So, as you see, method overloading in PHP5 is not as elegant as in Java, but you can still make it. For more information about ‘magic’ fucntions (there are quite a few for member overloading as well), please visit PHP Manual.