TalkPHP

TalkPHP (http://www.talkphp.com/forums.php)
-   Advanced PHP Programming (http://www.talkphp.com/advanced-php-programming/)
-   -   My Favourite PHP Magic Method: __call (http://www.talkphp.com/advanced-php-programming/1030-my-favourite-php-magic-method-__call.html)

Wildhoney 09-06-2007 09:02 PM

My Favourite PHP Magic Method: __call
 
Since the introduction of PHP5, us programmers have been treated to an abundance of magic methods. These are used in classes and provide extra functionality. They also tend to save a lot of time.

I'm here to introduce my favourite magic method, __call(). I use this predominantly within my database files (models in an MVC framework). It allows me to create the functions below without having to write them out individually as they all bring back effectively the same data.
  • getColumnByColumn()
  • isColumn()

The items highlighted in bold are the crucial parts of the string. The parts that are not bold are just there to give the function name some meaning.

Let's take my member class as a prime example. You often find yourself wanting to get just one column. I could write the functions out individually like so:
  • public function getUsernameByEmail($szUsername)
  • public function getBirthByName($szDate)

The above functions would, in essence, return to me an email from the first function, and the birth date from the second. However, to save on the fingers it'd be great to bundle those into one function - __call()!

We can compile the __call() function like so to accept our getSomethingBySomething() function and extract out the elements we need to query the database.

PHP Code:

public function __call($szName$aArgs null)
{
    if(
eregi('^get(.*)By(.*)$'$szName))
    {
        
$aKeywords = array();
        
preg_match_all('/^get(.*)By(.*)$/iU'strtolower($szName), $aKeywords);
    }
    
... 

That would extract the two items from out of the $szName variable and input it into $aKeywords array allowing me to query the database later on in the script. This is what happens when I create a __call() function and then call it using my snippet of code above:
  • I call a member function like: $pMember->getNameByEmail('test@demo.com');
  • PHP checks to see if the function getNameByEmail() exists, if not it checks to see if __call() exists.
  • Feed the getNameByEmail() into __call() as the first argument, and any arguments inside the parenthesis as the second argument as an array.
  • Checks to see if the first argument matches the regular expression pattern;
  • If it matches, extract the two table columns (name and email) from the string and then continue;
  • Query the database using the two previously extracted keywords and use the __call() function's second argument, $aArgs, to get the string to check the email column in the database for.
  • Return the data and proceed to echo out the data.

...And that's it! Your query is ready to be compiled like so:

PHP Code:

$szSQL sprintf("    SELECT `%s`
                    FROM `categories_list`
                    WHERE `%s` = %s
                    LIMIT 1"
,
                    
$aKeywords[1][0],
                    
$aKeywords[2][0],
                    
mysql_parse_value($aArgs[0])); 


Karl 09-06-2007 09:12 PM

Nice contribution Wildhoney. The magic functions are a great tool to have in your PHP development toolbox.

Haris 09-06-2007 10:06 PM

Wow, powerful.

bluesaga 09-06-2007 11:53 PM

The magic functions are extremely powerful and can be used to create some very impresive frameworks! Nice contribution!

jordie 09-13-2007 09:23 AM

Wow thats really cool :) I never thought of using it like that! At work we're trapped at PHP4 as we need to support as many server setups as possible, so I haven't delved into much of the php5 goodness.

Wildhoney 09-13-2007 10:36 AM

It's a fantastic release. Adds far too much to even consider remembering it all. PHP4 is very limited on the OOP side of things - but PHP5. Wow.

Tanax 11-03-2007 01:46 PM

PHP Code:

`categories_list

Is that supposed to be the table where the data is?
Cause what if you have several tables? :S

getUsernameByWarnings(5)

Ofcourse I could store the warnings in a column in the username table, but what if I don't(the warnings was just an example, I'm sure you get the point)??

How would I then be able to search the right table, by using this function?

Wildhoney 11-03-2007 02:23 PM

Well, this was based on an MVC pattern and so that function would be either cloned for every class that represents a table in the database, and so you would change the static table name manually. Or as an alternative, you could make the class central to everything and change the dynamic table name depending on which class you're calling it from.

Tanax 11-03-2007 04:25 PM

Yea, but let's say I have a membersclass that deals with all the members.
But I have several tables concerning the members.

Users
Warnings
Logs

For instance.
How would I then base that function on what class, since I'm in the membersclass, but I have several tables concerning the members? ://

Tanax 11-03-2007 05:13 PM

Actually I thought of something, the $aArgs is an array?

So if I do like:
PHP Code:

getUsernameByWarnings(5'warnings'); 

PHP Code:

            $sql sprintf("    SELECT `%s`
                    FROM `%s`
                    WHERE `%s` = %s
                    LIMIT 1"
,
                    
$aKeywords[1][0],
                    
mysql_parse_value($aArgs[1]),
                    
$aKeywords[2][0],
                    
mysql_parse_value($aArgs[0])); 

Wouldn't that work?

EDIT:
And that would get every user, who has 5 warnings, from the warnings table.

sunilbhatia79 11-16-2007 03:32 AM

PHP5 Magic Tutorials
 
I have developed a complete set of tutorials on PHP5 Magic Methods, you can read it here:

http://www.sunilb.com/category/php/php5-magic-methods

Hope this helps.

Also if you have any questions, please post them here or leave comments my blog.


All times are GMT. The time now is 08:43 AM.

Powered by vBulletin® Version 3.6.8
Copyright ©2000 - 2013, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.1.0