Tuesday, December 30, 2008

Magic Methods, __sleep , __wakeup, __toString, __set_state in PHP

Magic Methods

The function names __construct, __destruct (see Constructors and Destructors), __call, __callStatic, __get, __set, __isset, __unset (see Overloading), __sleep, __wakeup, __toString, __set_state and __clone are magical in PHP classes. You cannot have functions with these names in any of your classes unless you want the magic functionality associated with them



__sleep and __wakeup

serialize() checks if your class has a function with the magic name __sleep. If so, that function is executed prior to any serialization. It can clean up the object and is supposed to return an array with the names of all variables of that object that should be serialized. If the method doesn't return anything then NULL is serialized and E_NOTICE is issued.

The intended use of __sleep is to commit pending data or perform similar cleanup tasks. Also, the function is useful if you have very large objects which do not need to be saved completely.

Conversely, unserialize() checks for the presence of a function with the magic name __wakeup. If present, this function can reconstruct any resources that the object may have.

The intended use of __wakeup is to reestablish any database connections that may have been lost during serialization and perform other reinitialization tasks.


class Connection {
protected
$link;
private
$server, $username, $password, $db;

public function
__construct($server, $username, $password, $db)
{
$this->server = $server;
$this->username = $username;
$this->password = $password;
$this->db = $db;
$this->connect();
}

private function
connect()
{
$this->link = mysql_connect($this->server, $this->username, $this->password);
mysql_select_db($this->db, $this->link);
}

public function
__sleep()
{
return array(
'server', 'username', 'password', 'db');
}

public function
__wakeup()
{
$this->connect();
}
}
?>

__toString

The __toString method allows a class to decide how it will react when it is converted to a string.

Simple example

// Declare a simple class
class TestClass
{
public
$foo;

public function
__construct($foo) {
$this->foo = $foo;
}

public function
__toString() {
return
$this->foo;
}
}

$class = new TestClass('Hello');
echo
$class;
?>

The above example will output:

Hello
It is worth noting that before PHP 5.2.0 the __toString method was only called when it was directly combined with echo() or print(). Since PHP 5.2.0, it is called in any string context (e.g. in printf() with %s modifier) but not in other types contexts (e.g. with %d modifier). Since PHP 5.2.0, converting objects without __toString method to string would cause E_RECOVERABLE_ERROR.

__set_state

This static method is called for classes exported by var_export() since PHP 5.1.0.

The only parameter of this method is an array containing exported properties in the form array('property' => value, ...).

Using __set_state (since PHP 5.1.0)


class A
{
public
$var1;
public
$var2;

public static function
__set_state($an_array) // As of PHP 5.1.0
{
$obj = new A;
$obj->var1 = $an_array['var1'];
$obj->var2 = $an_array['var2'];
return
$obj;
}
}

$a = new A;
$a->var1 = 5;
$a->var2 = 'foo';

eval(
'$b = ' . var_export($a, true) . ';'); // $b = A::__set_state(array(
// 'var1' => 5,
// 'var2' => 'foo',
// ));
var_dump($b);

?>

The above example will output:

object(A)#2 (2) {
["var1"]=>
int(5)
["var2"]=>
string(3) "foo"
}




Object cloning in PHP

Object cloning

Creating a copy of an object with fully replicated properties is not always the wanted behavior. A good example of the need for copy constructors, is if you have an object which represents a GTK window and the object holds the resource of this GTK window, when you create a duplicate you might want to create a new window with the same properties and have the new object hold the resource of the new window. Another example is if your object holds a reference to another object which it uses and when you replicate the parent object you want to create a new instance of this other object so that the replica has its own separate copy.

An object copy is created by using the clone keyword (which calls the object's __clone() method if possible). An object's __clone() method cannot be called directly.

$copy_of_object = clone $object;

When an object is cloned, PHP 5 will perform a shallow copy of all of the object's properties. Any properties that are references to other variables, will remain references. If a __clone() method is defined, then the newly created object's __clone() method will be called, to allow any necessary properties that need to be changed.

Cloning an object

class SubObject
{
static
$instances = 0;
public
$instance;

public function
__construct() {
$this->instance = ++self::$instances;
}

public function
__clone() {
$this->instance = ++self::$instances;
}
}

class
MyCloneable
{
public
$object1;
public
$object2;

function
__clone()
{
// Force a copy of this->object, otherwise
// it will point to same object.
$this->object1 = clone $this->object1;
}
}

$obj = new MyCloneable();

$obj->object1 = new SubObject();
$obj->object2 = new SubObject();

$obj2 = clone $obj;


print(
"Original Object:\n");
print_r($obj);

print(
"Cloned Object:\n");
print_r($obj2);

?>

The above example will output:

Original Object:
MyCloneable Object
(
[object1] => SubObject Object
(
[instance] => 1
)

[object2] => SubObject Object
(
[instance] => 2
)

)
Cloned Object:
MyCloneable Object
(
[object1] => SubObject Object
(
[instance] => 3
)

[object2] => SubObject Object
(
[instance] => 2
)

)


Overloading in PHP

Overloading

Overloading in PHP provides means to dynamically "create" members and methods. These dynamic entities are processed via magic methods one can establish in a class for various action types.

The overloading methods are invoked when interacting with members or methods that have not been declared or are not visible in the current scope. The rest of this section will use the terms "inaccessible members" and "inaccessible methods" to refer to this combination of declaration and visibility.

All overloading methods must be defined as public.

Note: None of the arguments of these magic methods can be passed by reference.

Note: PHP's interpretation of "overloading" is different than most object oriented languages. Overloading traditionally provides the ability to have multiple methods with the same name but different quantities and types of arguments.

ChangeLog

Version Description
5.1.0 Added __isset() and __unset().
5.3.0 Added __callStatic(). Added warning to enforce public visibility and non-static declaration.

Member overloading

void __set ( string $name , mixed $value )
mixed __get ( string $name )
bool __isset ( string $name )
void __unset ( string $name )

__set() is run when writing data to inaccessible members.

__get() is utilized for reading data from inaccessible members.

__isset() is triggered by calling isset() or empty() on inaccessible members.

__unset() is invoked when unset() is used on inaccessible members.

The $name argument is the name of the member being interacted with. The __set() method's $value argument specifies the value the $name'ed member should be set to.

Member overloading only works in object context. These magic methods will not be triggered in static context. Therefore these methods can not be declared static.

Example #1 overloading with __get, __set, __isset and __unset example

class MemberTest {
/** Location for overloaded data. */
private $data = array();

/** Overloading not used on declared members. */
public $declared = 1;

/** Overloading only used on this when accessed outside the class. */
private $hidden = 2;

public function
__set($name, $value) {
echo
"Setting '$name' to '$value'\n";
$this->data[$name] = $value;
}

public function
__get($name) {
echo
"Getting '$name'\n";
if (
array_key_exists($name, $this->data)) {
return
$this->data[$name];
}

$trace = debug_backtrace();
trigger_error(
'Undefined property via __get(): ' . $name .
' in ' . $trace[0]['file'] .
' on line ' . $trace[0]['line'],
E_USER_NOTICE);
return
null;
}

/** As of PHP 5.1.0 */
public function __isset($name) {
echo
"Is '$name' set?\n";
return isset(
$this->data[$name]);
}

/** As of PHP 5.1.0 */
public function __unset($name) {
echo
"Unsetting '$name'\n";
unset(
$this->data[$name]);
}

/** Not a magic method, just here for example. */
public function getHidden() {
return
$this->hidden;
}
}


echo
"
\n";


$obj = new MemberTest;

$obj->a = 1;
echo
$obj->a . "\n\n";

var_dump(isset($obj->a));
unset(
$obj->a);
var_dump(isset($obj->a));
echo
"\n";

echo
$obj->declared . "\n\n";

echo
"Let's experiment with the private property named 'hidden':\n";
echo
"Privates are visible inside the class, so __get() not used...\n";
echo
$obj->getHidden() . "\n";
echo
"Privates not visible outside of class, so __get() is used...\n";
echo
$obj->hidden . "\n";
?>

The above example will output:

Setting 'a' to '1'

Getting 'a'
1

Is 'a' set?
bool(true)
Unsetting 'a'
Is 'a' set?
bool(false)

1

Let's experiment with the private property named 'hidden':
Privates are visible inside the class, so __get() not used...
2
Privates not visible outside of class, so __get() is used...
Getting 'hidden'


Notice: Undefined property via __get(): hidden in on line 70 in on line 29

Method overloading

mixed __call ( string $name , array $arguments )
mixed __callStatic ( string $name , array $arguments )

__call() is triggered when invoking inaccessible methods in an object context.

__callStatic() is triggered when invoking inaccessible methods in a static context.

The $name argument is the name of the method being called. The $arguments argument is an enumerated array containing the parameters passed to the $name'ed method.

Example #2 overloading instantiated methods with __call and ___callStatic

class MethodTest {
public function
__call($name, $arguments) {
// Note: value of $name is case sensitive.
echo "Calling object method '$name' "
. implode(', ', $arguments). "\n";
}

/** As of PHP 5.3.0 */
public static function __callStatic($name, $arguments) {
// Note: value of $name is case sensitive.
echo "Calling static method '$name' "
. implode(', ', $arguments). "\n";
}
}

$obj = new MethodTest;
$obj->runTest('in object context');

MethodTest::runTest('in static context'); // As of PHP 5.3.0
?>

The above example will output:

Calling object method 'runTest' in object context

Calling static method 'runTest' in static context

Wednesday, December 24, 2008

Free PHP books links

http://rapidshare.com/files/128636166/04_-_PHP_5_and_MySQL_Bible.rar

http://rapidshare.com/files/128637790/09_-_PHP_Professional_Projects.rar

http://rapidshare.com/files/144017451/Ajax_in_Action.pdf

http://rapidshare.com/files/143551939/Beginning_PHP_and_MySQL_5_From_Novice_to_Professional.pdf

http://rapidshare.com/files/144018301/Beginning_XML_With_DOM_And_Ajax_-_From_Novice_To_Professional.pdf

http://rapidshare.com/files/128391727/Building_Online_Communities_With_Drupal__Phpbb_And_Wordpress.pdf

http://rapidshare.com/files/144017621/Dreamweaver_CS3_with_CSS_Ajax_and_PHP.part1.rar
http://rapidshare.com/files/144017789/Dreamweaver_CS3_with_CSS_Ajax_and_PHP.part2.rar

http://rapidshare.com/files/133735694/Foundations_of_PEAR_Rapid_PHP_Development.pdf

http://rapidshare.com/files/128392357/Learning_Drupal_6_Module_Development_2008.pdf

http://rapidshare.com/files/143548475/PHP5_CMS_Framework_Development.pdf

http://rapidshare.com/files/143550423/PHP_and_MySQL_-__Create-Modify-Reuse.pdf

http://rapidshare.com/files/143550793/PHP_Objects__Patterns__and_Practice.pdf

http://rapidshare.com/files/144016785/Understanding_AJAX_-_Using_JavaScript_To_Create_Rich_Internet_Applications.chm

http://rapidshare.com/files/128392179/Pro_Drupal_Development_2007.pdf

http://rapidshare.com/files/143549330/Secure_PHP_Development_Building_50_Practical_Applications.pdf

http://rapidshare.com/files/143549916/Teach_Yourself_Php__Mysql_And_Apache_All_In_One.chm

http://rapidshare.com/files/144017964/Practical_JavaScript__DOM_Scripting__and_Ajax_Projects.part1.rar
http://rapidshare.com/files/144018096/Practical_JavaScript__DOM_Scripting__and_Ajax_Projects.part2.rar

http://rapidshare.com/files/143549629/Practical_Web_2.0_Applications_with_PHP.pdf

http://rapidshare.com/files/133735694/Foundations_of_PEAR_Rapid_PHP_Development.pdf


http://rapidshare.com/files/128637790/09_-_PHP_Professional_Projects.rar

http://rapidshare.com/files/128636166/04_-_PHP_5_and_MySQL_Bible.rar

Tuesday, July 29, 2008

php oops - object oriented programming languages

Object Oriented Programming (OOP) in PHP. I will show you how to code less and better by using some OOP concepts and PHP tricks. Good luck!
Concepts of object oriented programming: There're differences between authors, I can mention that a OOP language must have:

* Abstract data types and information hidding
* Inheritance
* Polymorphism

The encapsulation is done in php using classes:

x=$v;
}

function getX() {
return $this->x;
}
}

?>
Data members are defined in php using a "var" declaration inside the class, data members have no type until they are assigned a value. A data member might be an integer, an array, an associative array or even an object. Methods are defined as functions inside the class, to access data members inside the methods you have to use $this->name, otherwise the variable is local to the method.

You create an object using the new operator:
$obj=new Something;
Then you can use member functions by:
$obj->setX(5);
$see=$obj->getX();

The setX member function assigns 5 to the x datamember in the object obj (not in the class), then getX returns its value: 5 in this case.
You can access the datamembers from the object reference using for example: $obj->x=6; however, this is not a very good OOP practice. I enforce you to set datamembers by defining methods to set them and access the datamembers by using retrieving methods. You'll be a good OOP programmer if you consider data members inaccesible and only use methods from the object handler. Unfortunately PHP doesn't have a way to declare a data member private so bad code is allowed.
Inheritance is easy in php using the extend keyword.

y=$v;
}

function getY() {
return $this->y;
}
}

?>
Objects of the class "Another" now has all the data members and methods of the parent class (Something) plus its own data members and methods. You can use:
$obj2=new Something;
$obj2->setX(6);
$obj2->setY(7);

Multiple inheritance is not supported so you can't make a class extend two or more different classes.

You can override a method in the derived class by redefining it, if we redefine getX in "Another" we can't no longer access method getX in "Something". If you declare a data member in a derived class with the same name as a data member in a Base class the derived data member "hides" the base class data member when you access it.
You might define constructors in your classes, constructors are methods with the same name as the class and are called when you create an object of the class for example:

x=$y;
}

function setX($v) {
$this->x=$v;
}

function getX() {
return $this->x;
}
}

?>
So you can create an object by:
$obj=new Something(6);
And the constructor automatically asigns 6 to the data member x.
Constructors and methods are normal php functions so you can use default arguments.

function Something($x="3",$y="5")
Then:

$obj=new Something(); // x=3 and y=5
$obj=new Something(8); // x=8 and y=5
$obj=new Something(8,9); // x=8 and y=9

Default arguments are used in the C++ way so you can't pass a value to Y and let X take the default value, arguments are asigned form left to right and when no more arguments are found if the function expected more they take the default values.
When an object of a derived class is created only its constructor is called, the constructor of the Parent class is not called, this is a gotcha of PHP because constructor chaining is a classic feature of OOP, if you want to call the base class constructor you have to do it explicitely from the derived class constructor.It works because all methods of the parent class are available at the derived class due to inheritance.

y=5;
$this->Something(); //explicit call to base class constructor.
}

?>
A nice mechanism in OOP is to use Abstract Classes,
abstract classes are classes that are not instanciable and has the only purpose to define an interface for its derived classes. Designers often use Abstract classes to force programmers to derive classes from certain base classes so they can be certain that the new classes have some desired functionality. There's no standard way to do that in PHP but:



Overloading (which is different from overriding) is not supported in PHP. In OOP you "overload" a method when you define two/more methods with the same name but different number or type of parameters (depending upon the language). Php is a loosely typed language so overloading by types won't work, however overloading by number of parameters doesn't work either.
It's very nice sometimes in OOP to overload constructors so you can build the object in different ways (passing different number of arguments). A trick to do something like that in PHP is:

$name();
//Note that $this->$name() is usually wrong but here
//$name is a string with the name of the method to call.
}

function Myclass1($x) {
code;
}
function Myclass2($x,$y) {
code;
}
}

?>
With this extra working in the class the use of the class is transparent to the user:

$obj1=new Myclass('1'); //Will call Myclass1
$obj2=new Myclass('1','2'); //Will call Myclass2

Polymorphism is defined as the ability of an object to determine which method to invoke for an object passed as argument in runtime time. For example if you have a class figure which defines a method draw and derived classes circle and rectangle where you override the method draw you might have a function which expects an argument x and then call $x->draw(). If you have polymorphism the method draw called depends of the type of object you pass to the function. Polymorphism is very easy and natural in interpreted languages as PHP (try to imagine a C++ compiler generating code for this case, which method do you call? You don't know yet which type of object you have!, ok this is not the point). So PHP happily supports polymorphism.

draw();
}

$obj=new Circle(3,187);
$obj2=new Rectangle(4,5);

$board->niceDrawing($obj); //will call the draw method of Circle.
$board->niceDrawing($obj2); //will call the draw method of Rectangle.

?>
OOP Programming in PHP
Some "purists" will say PHP is not truly an object oriented language, which is true. PHP is a hybrid language where you can use OOP and traditional procedural programming. For large projects, however, you might want/need(?) to use "pure" OOP in PHP declaring classes, and using only objects and classes for your project. As larger and larger projects emerge the use of OOP may help, OOP code is easy to mantain, easy to understand and easy to reuse. Those are the foundations of software engineering.

Advanced OOP Techniques in PHP
After reviewing the basic concepts of OOP I can show you some more advanced techniques:

Serializing
PHP doesn't support persistent objects, in OOP persistent objects are objects that keep its state and funcionality across multiple invocations of the application, this means having the ability of saving the object to a file or database and then loading the object back. The mechanism is known as serialization. PHP has a serialize method which can be called for objects, the serialize method returns a string representation of the object. However serialize saves the datamembers of the object but not the methods.

In PHP4 if you serialize the object to string $s, then destroy the object, and then unserialize the object to $obj you might still access the object methods! I don't recommend this because (a) The documentation doesn't guarrantee this beahaviour so in future versions it might not work. (b) This might lead to 'illusions' if you save the serialized version to disk and exit the script. In future runs of the script you can't unserialize the string to an object an expect the methods to be there because the string representation doesn't have the methods! Summarizing serializing in PHP is VERY useful to save the data members of an object just that. (You can serialize asociative arrays and arrays to save them to disk too).
Example:


You have the datamembers recovered but not the methods (according to the documentation). This leads to $obj2->x as the only way to access the data members (you have no methods!) so don't try this at home.
There're some ways to fix the problem, I leave it up to you because they are too dirty for this neat article.
Full serialization is a feature I'd gladly welcome in PHP.

Using Classes to Manipulate Stored Data
One very nice thing of PHP and OOP is that you can easily define classes to manipulate certain things and the call the appropiate classes whenever you want. Suposse you have a html form where the user selects a product by selecting it's product ID, you have the data of the products in a database and you want to display the product, show its price, etc etc. You have products of different types, and the same action might have different meanings for different kind of products. For example showing a sound might mean playing it while for some other kind of products might mean to display a picture stored in the database. You might use OOP and PHP to code less and code better:

Define a class product, define which methods the class should have (example display), then define classes for each type of product which extends the product class (class SoundItem, class ViewableItem, etc...) override the methods you define in product in each of this classes make them do what you want. Name the classes according to the "type" column you store in the database for each product a typical product table might have (id,type,price,description,etc etc)... Then in the processing script you can retrieve the type from the database and instanciate an object of the class named type using:

action();

?>
This is a very nice feature of PHP, you might then call the display method of $obj or any other method regardless the type of object you have. With this technique you don't have to touch the processing script when you add a new type of object, just add a class to handle it. This is quite powerful, just define the methods all objects regardless of its type should have, implement them in different ways in different classes and use them for any type of object in the main script, no ifs, no 2 programmers in the same file, eternal happiness.

Do you agree programming is easy, mainteinance is cheaper and reusability is real now?

If you command a group of programmers is easy to divide the tasks, each one might be responsable for a type of object and the class that handles it. Internacionalization can be done using this technique, apply the proper class according to a language field selected by the user, etc.

Copying and Cloning
When you create an object $obj you can copy the object by doing $obj2=$obj, the new object is a copy (not a reference) of $obj so it has the state $obj had in the moment the assignment was made. Sometimes you don't want this, you just want to create a new object of the same class as obj, calling the constructor of the new object as if you had used the new statement. This can be done in PHP using serialization and a base class that all other classes must extend.

Entering a Danger Zone
When you serialize an object you get a string which has a certain format, you may investigate it if you are curious, one of the things the string has is the name of the class (nice!) you may extract it using:


So suposse you create a class "Universe" and force that all classes must extend universe, you can define a method clone in Universe as:

clone();

?>
What you get is a new object of class Something created the same way as using new, the constructor is called, etc. I don't know if this is useful for you, but the Universe class which knows the name of the derived class is a nice concept to experiment. The only limit is your imagination.