php 5 oop gotchas you must know

I was reading php 5 oop stuffs from http://php.net site, few things i noted for myself, these you should learn too if aren’t yet, so go on. These notes taken from php.net –

Inheritance – It is not possible to extend multiple classes; a class can only inherit from one base class.

Static – To access a static property, we can use self var inside class like echo self::$foo;

Properties
Any property inside a class can has initial value but that should be static only, no expression.

// invalid property declarations: heredoc  
   public $var2 = <<<EOD
hello world
EOD;
   // This is allowed only in PHP 5.3.0 and later. nowdoc
   public $var8 = <<<'EOD'
hello world
EOD;

Class Constant
The value must be a constant expression, not (for example) a variable, a property, a result of a mathematical operation, or a function call. Can be accessible like static properties

class MyClass
{
    const constant = 'constant value';

    function showConstant() {
        echo  self::constant . "\n";
    }
}

Autoload – Prior to 5.3.0, exceptions thrown in the __autoload function could not be caught in the catch block and would result in a fatal error. It works for interface too. From 5.3.0+ exceptions thrown in the __autoload function can be caught in the catch block, with 1 proviso. If throwing a custom exception, then the custom exception class must be available.

Autoload doesnt work in PHP CLI interactive mode.

SPL Mulitple Autoloads

<?php

    /*** nullify any existing autoloads ***/
    spl_autoload_register(null, false);

    /*** specify extensions that may be loaded ***/
    spl_autoload_extensions('.php, .class.php, .lib.php');

    /*** class Loader ***/
    function classLoader($class)
    {
        $filename = strtolower($class) . '.class.php';
        $file ='classes/' . $filename;
        if (!file_exists($file))
        {
            return false;
        }
        include $file;
    }

    function libLoader($class)
    {
        $filename = strtolower($class) . '.lib.php';
        $file ='libs/' . $filename;
        if (!file_exists($file))
        {
            return false;
        }
        include $file;
    }

    /*** register the loader functions ***/
    spl_autoload_register('classLoader');
    spl_autoload_register('libLoader');

    /*** a new instance of norman ***/
    $norman = new norman;

    /*** make norman do some thing ***/
    $norman->do_something();

Constructor
Parent constructors are not called implicitly if the child class defines a constructor. In order to run a parent constructor, a call to parent::__construct() within the child constructor is required.

Overriding rules :
1. In the overriding, the method names and arguments (arg’s) must be same.
2. Final methods can’t be overridden.
3. Properties cannot be declared final, only classes and methods may be declared as final.

Strict Inheritance
When you define a class with abstract, any attempt to instantiate a separate instance of it will result in a fatal error.

Paamayim Nekudotayim(in Hebrew):
The Scope Resolution Operator (also called Paamayim Nekudotayim) or in simpler terms, the double colon, is a token that allows access to static, constant, and overridden properties or methods of a class.

Class Name in a variable:
As of PHP 5.3.0, it’s possible to reference the class using a variable. Example –

<?php
class MyClass {
    const CONST_VALUE = 'A constant value';
}

$classname = 'MyClass';
echo $classname::CONST_VALUE; // As of PHP 5.3.0

Static
A property declared as static can not be accessed with an instantiated class object. The pseudo-variable $this is not available inside the method declared as static.

Abstract Class, sample code


<?php
	abstract class AbstractClass{
		abstract protected function getValue();
		abstract protected function prefixValue($prefix);
		
		public function printOut(){
			print $this->getValue()."\n";
		}
	}

	class ConcreteClass1 extends AbstractClass{
		protected function getValue(){
			return "ConcreteClass1";
		}
		
		public function prefixValue($prefix){
			return "{$prefix}ConcreteClass1";
		}
	}
	
	class ConcreteClass2 extends AbstractClass{
		public function getValue(){
			return "ConcreteClass2";
		}

		public function prefixValue($prefix){
			return "{$prefix}ConcreteClass2";
		}		
		
	}
	
	$class1 = new ConcreteClass1;
	$class1->printOut();
	echo $class1->prefixValue('FOO_')."\n";
	
	$class2 = new ConcreteClass2;
	$class2->printOut();
	echo $class2->prefixValue('FOO_')."\n";
	

Interface – All methods declared in an interface must be public. Interface supports multiple inheritance, multiple implements if both interface dont have same function name. See example –

interface a
{
    public function foo();
}

interface b
{
    public function bar();
}

interface c extends a, b
{
    public function baz();
}

class d implements c
{
    public function foo()
    {
    }

    public function bar()
    {
    }

    public function baz()
    {
    }
}

OverloadingOverloading traditionally provides the ability to have multiple methods with the same name but different quantities and types of arguments. but overloading in PHP provides means to dynamically “create” properties and methods using magic methods.
Property Overloading methods are __set, __get, __isset, __unset
Method Overloading methods are __call, __callStatic
All overloading methods must be defined as public.

Iterator – Php has two new built in interfaces – iterator and IteratorAggregate, using these – its easy to iterate a object. Object Iteration implementing Iterator –


<?php
class MyIterator implements Iterator
{
    private $var = array();

    public function __construct($array)
    {
        if (is_array($array)) {
            $this->var = $array;
        }
    }

    public function rewind() {
        echo "rewinding\n";
        reset($this->var);
    }

    public function current() {
        $var = current($this->var);
        echo "current: $var\n";
        return $var;
    }

    public function key() {
        $var = key($this->var);
        echo "key: $var\n";
        return $var;
    }

    public function next() {
        $var = next($this->var);
        echo "next: $var\n";
        return $var;
    }

    public function valid() {
        $var = $this->current() !== false;
        echo "valid: {$var}\n";
        return $var;
    }
}

$values = array(1,2,3);
$it = new MyIterator($values);

foreach ($it as $a => $b) {
    print "$a: $b\n";
}
?>

Patterns – Patterns are ways to describe best practices and good designs.
The Factory pattern allows for the instantiation of objects at runtime. Example –

<?php
class Example
{
    // The parameterized factory method
    public static function factory($type)
    {
        if (include_once 'Drivers/' . $type . '.php') {
            $classname = 'Driver_' . $type;
            return new $classname;
        } else {
            throw new Exception('Driver not found');
        }
    }
}

// Load a MySQL Driver
$mysql = Example::factory('MySQL');

// Load a SQLite Driver
$sqlite = Example::factory('SQLite');

?>

The Singleton pattern applies to situations in which there needs to be a single instance of a class. Example –

<?php
class Example
{
    // Hold an instance of the class
    private static $instance;
    
    // A private constructor; prevents direct creation of object
    private function __construct() 
    {
        echo 'I am constructed';
    }

    // The singleton method
    public static function singleton() 
    {
        if (!isset(self::$instance)) {
            $c = __CLASS__;
            self::$instance = new $c;
        }

        return self::$instance;
    }
    
    // Example method
    public function bark()
    {
        echo 'Woof!';
    }

    // Prevent users to clone the instance
    public function __clone()
    {
        trigger_error('Clone is not allowed.', E_USER_ERROR);
    }

}

// This would fail because the constructor is private
$test = new Example;

// This will always retrieve a single instance of the class
$test = Example::singleton();
$test->bark();

// This will issue an E_USER_ERROR.
$test_clone = clone $test;
?>

Magic Methods – *PHP reserves all function names starting with __ as magical.
__construct –
In order to run a parent constructor, a call to parent::__construct() within the child constructor is required.
__destruct – The destructor method will be called as soon as all references to a particular object are removed or when the object is explicitly destroyed or in any order in shutdown sequence.
__call is triggered when invoking inaccessible methods in an object context.
__callStatic is triggered when invoking inaccessible methods in a static context.
__set() is run when writing data to inaccessible properties.
__get() is utilized for reading data from inaccessible properties.
__isset() is triggered by calling isset() or empty() on inaccessible properties.
__unset() is invoked when unset() is used on inaccessible properties.
__sleep() – 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.
__wakeup – 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.
__sleep and __wakeup example –

<?php
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 method allows a class to decide how it will react when it is converted to a string.

<?php
// 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;
?>

__invoke method is called when a script tries to call an object as a function

<?php
class CallableClass {
    function __invoke($x) {
        var_dump($x);
    }
}
$obj = new CallableClass;
$obj(5);
var_dump(is_callable($obj));
?>

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

Object Cloning – 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.
Once the cloning is complete, 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.

Type Hinting – Functions are now able to force parameters to be objects (by specifying the name of the class in the function prototype) or arrays. However, if NULL is used as the default parameter value, it will be allowed as an argument for any later call. Failing to satisfy the type hint results in a catchable fatal error. Type hinting also works with functions:

<?php
// An instance of each class
$myclass = new MyClass;
$otherclass = new OtherClass;

// Fatal Error: Argument 1 must be an object of class OtherClass
$myclass->test('hello');

// Fatal Error: Argument 1 must be an instance of OtherClass
$foo = new stdClass;
$myclass->test($foo);

// Fatal Error: Argument 1 must not be null
$myclass->test(null);

// Works: Prints Hello World
$myclass->test($otherclass);

// Fatal Error: Argument 1 must be an array
$myclass->test_array('a string');

// Works: Prints the array
$myclass->test_array(array('a', 'b', 'c'));
?>

Late Static Binding – can be used to reference the called class in a context of static inheritance. Example

<?php
class A {
    public static function who() {
        echo __CLASS__;
    }
    public static function test() {
        static::who(); // Here comes Late Static Bindings
    }
}

class B extends A {
    public static function who() {
        echo __CLASS__;
    }
}

B::test();
?>

This will output “B”

Object Serialization – It serialize only vars and classname, not any method. Also to unserialize that value – that class file of that object should be include first.

Advertisements

4 thoughts on “php 5 oop gotchas you must know

  1. Hey kodegeek, nice to know another geek in php_geekeeland 😉
    Cheers for your blog!

    Good listing of some main points..
    Else I would just re-frame this part concerning the factory pattern line:
    “..for the instantiation of objects at runtime..” into “..for the instantiation of classes at runtime..”.
    It might be fine, but I think we say ‘instantiate a class and an object is an instantiation’.
    But i’m sure your idea has been correctly conveyed 😉

    Cheers!

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s