Zend PHP5 certification Exam study review 8: OOP In PHP 5

Object Oriented Programming is the norm in modern software programming. Sadly, prior PHP4, PHP lack a great OOP language support. PHP5 changes all that. That’s why the Exam has two topics especially regarding this area: the actual OOP feature in PHP5 and OOP design and theory. This post is a brief review on PHP5 OOP feature, you will spent some time on OOP in PHP if you are a well experienced structure-style programmer in PHP4 I think. OOP is actually easier once you shift you ideas around :). Because, in life, not in one moment, we are not dealing with OBJECTS.
Prior to PHP5 OOP was a hack on top of the array implementation. PHP5 Changed everything, in a great way.

Objects are treated differently from other types of variables. An object is always passed by reference (in reality, it is passed by handle, but for all practical purposes there is no difference), rather than by value.

Parent classes can be accessed using the special parent:: namespace

$this.

One of the drawbacks of The constructor name is same with the name of the class. If you decided to rename your class, you would also have to rename your constructor. To avoid these problems, PHP 5 now uses the magic __construct() method as the constructor for any class regardless of the class’ name.
Note that, if the __construct() method is not found, PHP will look for the old PHP 4-style constructor and call that instead.

In addition to the __construct() method, we also have a __destruct() method.

Destruction occurs when all references to an object are gone, and this may not necessarily take place when you expect it—or even when you want it to. In fact, while you can unset() a variable that references an object, or overwrite it with another value, the object itself may not be destroyed right away because a reference to it is held elsewhere.

Even if an object still has one or more active references, the __destruct() method is called at the end of script execution—therefore, you are guaranteed that, at some point, your destructor will be executed. However, there is no way to determine the order in which any two objects in your scripts will be destroyed. This can sometimes cause problems when an object depends on another to perform one or more functions—for example, if one of your classes encapsulates a database connection and another class needs that connection to flush it data to the database, you should not rely on your destructors to perform a transparent flush to the database when the object is deleted: the instance of the first class that provides database connectivity could, in fact, be destroyed before the second, thus making it impossible for the latter to save its data to the database.

.public Method or property can be accessed externally.
.protected Method or property is private to that class and can not be accessed externally.
.private Method or property is private and can’t also be accessed by extending classes.
.final The final visibility level only applies to methods and classes. Classes that are declared as final cannot be extended.

Typically, you will want to make all API methods and properties public, since you will want them to be accessible from outside of your objects, while you will want to keep those used for internal operation as helpers to the API calls protected or private.

Constructors and Destructors—along with all other magic methods will normally be declared as public; there are, however, times when you wish to make the constructor private( e.g. certain design patterns like Singleton or Factory.).

Other Magic methods (Special Functions):
__construct()
__destruct()
__toString()
__sleep()
__wakeup()
__call()
__get()
__set()

Note that, like a normal variable, a class property can be initialized while it is being declared. However, the initialization is limited to assigning values (but not by evaluating expressions). You can’t, for example, initialize a variable by calling a function—that’s something you can only do within one of the class’ methods (typically, the constructor).

Constants, Static
Unlike regular methods and properties, their static counterparts exist and are accessible as part of a class itself, as opposed to existing only within the scope of one of its instances. This allows you to treat classes as true containers of interrelated functions and data elements—which, in turn, is a very handy expedient to avoid naming conflicts.
You should keep in mind that PHP 5 is very strict about the use of static properties and methods. For example, calling static properties using object notation will result in a notice:

class foo {
static $bar = “bat”;
static public function baz()
{
echo “Hello World”;
}
}
$foo = new foo();
$foo->baz();
echo $foo->bar;

It is necessary for the static definition to follow the visibility definition; if no visibility definition is declared, the static method or property is considered public.

Class constants are public, and accessible from all scopes.

Note that class constants suffer from the same limitations as regular constants—therefore, they can only contain scalar values.
Class constants have several advantages over traditional constants:
.since they are encapsulated in a class, they make for much cleaner code.
.they are significantly faster than those declared with the define() construct.

Interfaces & Abstract Classes
.New feature added to PHP 5
.Be used to create a series of constraints on the base design of a group of classes.

An abstract class essentially defines the basic skeleton of a specific type of encapsulated entity.
You must declare a class as abstract so long as it has (or inherits without providing a body) at least one abstract method.

Interfaces are used to specify an API that a class must implement. This allows you to create a common “contract” that your classes must implement in order to satisfy certain logical requirements.

If you fail to define all of the methods for a particular interface, or all of the arguments for any given interface method, you will see something ugly.

It is possible to implement more than one interface in the same class.

Additionally, a class can extend another class, as well as implement multiple interfaces at the same time.

Remember—a class can only extend one parent class, but it can implement multiple interfaces.

The instanceof operator

instanceof allows you to inspect all of the ancestor classes of your object, as well as any interfaces.

Exceptions
Exceptions provide an error control mechanism that is more fine-grained than traditional PHP fault handling, and that allows for a much greater degree of control.

.Unified method of error handling
.Makes proper error handling possible
.Can be accomplished with try catch blocks or by setting a unified error handler once
.Try catch blocks take precedence if the error raising code is within them.

.Exceptions are objects, created (or “thrown”) when an error occurs.
.Exceptions can be handled at different points in a script’s execution, and different types of exceptions can be handled by separate portions of a script’s code.
.All unhandled exceptions are fatal.
.Exceptions can be thrown from the __construct method on failure.
.Exceptions change the flow of the application.

Exception base class is built into PHP itself.

class Exception {
// The error message associated with this exception
protected $message = ’Unknown Exception’;
// The error code associated with this exception
protected $code = 0;
// The pathname of the file where the exception occurred
protected $file;
// The line of the file where the exception occurred
protected $line;
// Constructor
function __construct ($message = null, $code = 0);
// Returns the message
final function getMessage();
// Returns the error code
final function getCode();
// Returns the file name
final function getFile();
// Returns the file line
final function getLine();
// Returns an execution backtrace as an array
final function getTrace();
// Returns a backtrace as a string
final function getTraceAsString();
// Returns a string representation of the exception
function __toString();
}

Almost all of the properties of an Exception are automatically filled in for you by the interpreter—generally speaking, you only need to provide a message and a code, and all the remaining information will be taken care of for you.

The throw construct
Although it is common practice to do so, you don’t need to create the Exception object directly in the throw expression.

Exceptions then “bubble up” until they are either handled by the script or cause a fatal exception. The handling of exceptions is performed using a try…catch block.

try {
if ($error) {
throw new Exception (“This is my error”);
}
} catch (Exception $e) {
// Handle exception
}

Note how the catch() portion of the statement requires us to hint the type of Exception that we want to catch; one of the best features of exceptions is the fact that you can decide which kind of exception to trap.

Since you are free to extend the base Exception class, this means that different nested or Chained try..catch blocks can be used to trap and deal with different types of errors.

Once an exception has been caught, execution of the script will follow from directly after the last catch block.To avoid fatal errors from uncaught exceptions, you could wrap your entire application in a try… catch block—which would, however, be rather inconvenient. Luckily, there is a better solution—PHP allows us to define a “catch-all” function that is automatically called whenever an exception is not handled. This function is set up by calling set_exception_handler().

function handleUncaughtException($e)
{echo $e->getMessage();
}
set_exception_handler(“handleUncaughtException”);
throw new Exception(“You caught me!”);
echo “This is never displayed”;

Note that, because the catch-all exception handler is only called after the exception has bubbled up through the entire script, it, just like an all-encompassing try… catch block, is the end of the line for your code—in other words, the exception has already caused a fatal error, and you are just given the opportunity to handle it, but not to recover from it. For example, the code above will never output “This is never displayed”!, because the exception thrown will bubble up and cause handleUncaughtException() to be executed; the script will then terminate.

If you wish to restore the previously used exception handler, be it the default of a fatal error or another user defined callback, you can use restore_exception_handler().

Lazy Loading
Prior to PHP 5, instantiating an undefined class, or using one of its methods in a static way would cause a fatal error. This meant that you needed to include all of the class files that you might need, rather than loading them as they were needed—just so that you wouldn’t forget one—or come up with complicated file inclusion mechanisms to reduce the needless processing of external files.To solve this problem, PHP 5 features an “autoload” facility that makes it possible to implement “lazy loading”, or loading of classes on-demand. When referencing a non-existent class, be it as a type hint, static call, or attempt at instantiating an object, PHP will try to call the __autoload() global function so that the script may be given an opportunity to load it. If, after the call to autoload(), the class is still not defined, the interpreter gives up and throws a fatal error.

function __autoload($class)
{
// Require PEAR-compatible classes
require_once str_replace(“_”, “/”, $class);
}
$obj = new Some_Class();

When instantiating Some_Class, __autoload() is called and passed “Some_Class.php” as its argument. The function then replaces the underscores with forward slashes, and includes the file using require_once(). Using __autoload() is of great help when you are working with only one naming scheme; it allows lazy-loading of classes, so that classes that are never used are also never loaded. However, once you start mixing code and using different libraries (e.g.: PEAR and some legacy application) you will rapidly run into cases that __autoload() cannot handle without becoming too bulky and slow. The Standard PHP Library (SPL), luckily, offers a simpler solution to this problem by allowing you to stack autoloaders on top of each other.If one fails to load a class, the next one in the chain is called, until either the class has been loaded, or no more autoloaders are part of the chain (in which case, a fatal error occurs).

The default spl_autoload()
this built-infunction checks all include paths for filenames that match the name of the class that needs loading in lowercase letters, followed by .inc, .php, or the extensions specified using a comma-separated string as the only parameter to a call to spl_autoload_extensions().

Additional autoloaders can be added to the stack by calling spl_autoload_register().
The first call to this function replaces the __autoload() call in the engine with its own implementation—this means that, if you already have a user-defined __autoload() you will need to register it with SPL in order for it to continue working.

spl_autoload_register(’spl_autoload’);
if (function_exists(’__autoload’)) {
spl_autoload_register(’__autoload’);
}

Typehinting
Class can serve as typehinting.

Reflection
The reflection API provides a manner to obtain detailed information about code.

With PHP’s new object model comes the Reflection API a collection of functions and objects that allows you to examine the contents of a script’s code, such as functions and objects, at runtime.

Reflection can be very handy in a number of circumstances; for example, it can be used to generate simple documentation, or for determining whether certain functionality is available to a script, and so on.

get_defined_functions()

ReflectionFunction
ReflectionClass
ReflectionMethod

http://php.net/reflection

OOP Conclusions
.Slower than procedural code, but allows complex tasks to be understood more readily
.Data and related methods are grouped into one cohesive structure
.Multiple instances of the same object can be created
.Objects are now dealt with by reference rather than by value, objects must be explicitly cloned to be copied

5 Comments - Leave a comment
  1. Henry Lu says:

    Hi admin,
    Thank you for your post. It is a good article for ZCE review.

    I just have a question to ask you. In the following code you mentioned, why it will never output You caught me? I think it shouldn’t output ‘This is never displayed’. Could you tell me the reason if I am wrong.

    function handleUncaughtException($e)
    {echo $e->getMessage();
    }
    set_exception_handler(”handleUncaughtException”);
    throw new Exception(”You caught me!”);
    echo “This is never displayed”;

  2. David Adam says:

    Oops, you are right. Yes, it is obvious that the “This is never displayed” is never displayed! :)

  3. jo says:

    Hi admin,

    I have a question, please give me a help,

    Q: The __method is automatically called when the object is created, while the __ method is automatically when the object is destroyed.
    A:
    1.__construct(), __destruct()
    2., __destroy()
    3., ~
    4.__startup(), _ shutdown()
    5.__construct(), __destroy()

    my answer is 5.. is it correct?

  4. […] Object Oriented Programming in PHP 5 […]

Leave a Reply

Your email address will not be published. Required fields are marked *

*