x
Loading
 Loading

In With the New PHP

PHP (a recursive acronym for Hypertext Preprocessor) is an open source language platform widely-used for web development. Thanks in part to its simplicity, power, and compatibility with a wide variety of web servers and operating systems, PHP has rapidly become one of the most popular scripting environments in the world, exceeding all other scripting technologies.

Community Tools
RSS
Recommend This [?]
1 Star2 Stars3 Stars4 Stars5 Stars (No Ratings Yet)
Loading ... Loading ...
Users That Liked This [?]
No one yet. Be the first.
Tags:
Tag This!
 No Comments

PHP (a recursive acronym for Hypertext Preprocessor) is an open source language platform widely-used for web development. Thanks in part to its simplicity, power, and compatibility with a wide variety of web servers and operating systems, PHP has rapidly become one of the most popular scripting environments in the world, exceeding all other scripting technologies.

Even though the current “stable” version of PHP (4.3 as of the time of this writing) is in use by several million websites, the PHP development team — a very active community of volunteers, whose efforts are spearheaded by Zend Technologies (http://www.zend.com), an Israeli company whose co-founders are responsible for the development of the the Zend Engine, the underlying interpreter on which PHP runs — is hard at work preparing the next generation of the platform, PHP 5.

This month, let’s look at some of the major new features in PHP 5. One caveat: with a release date that may very well stretch into 2004, some of the features discussed here could change or be scrapped altogether before the final version of PHP 5 is released.

PHP: Now with True Class(es)

Perhaps the most significant change in the Zend Engine is the introduction of a modern object-oriented programming (OOP) model. Although PHP 4 supports some level of OOP, it was almost an afterthought, resulting in a rather weak, but nonetheless popular implementation, even with all of its limitations.

In PHP, an object is treated just like any other scalar value: it’s copied whenever the object is assigned to a variable. While it makes variables in PHP behave consistently, copying an object isn’t particularly obvious or intuitive to someone that’s used OOP in another language.

Consider, for example, this brief script:

<?php
class a {
  var $test;
}

$a = new a;
$a->test = 10;
echo $a->test;  // Prints 10

$b = $a;
$b->test = 12;
echo $a->test;// Prints 10 again!
?>

In another object-oriented environment (such as Java), one would expect the value of $a->test to change when $b->test = 12 is executed, since, traditionally, objects are always handled by reference. But in PHP 4, objects are considered simple scalars; therefore the instruction $b = $a causes a physical copy of $a to be stored in $b.

Now, this “problem” can, in part, be solved by passing values by reference rather than by value. If you change the code $b = $a to $b = &$a, everything works as you might expect, as $a->test will be 12 after $b->test is changed. However, writing code this way is very counterintuitive, and it’s very easy to cause hard-to-find bugs by simply forgetting to put an ampersand in the right place.

With the new Zend Engine built into PHP 5, objects are treated as a special type of variable that’s always passed by reference, and the script above works exactly like you’d expect it to (coming from a traditional OOP environment).

Naturally, this brings up a new problem in PHP 5: how do you create a physical copy of an object? In PHP 5, the Zend Engine provides a copy constructor just for that purpose. Here’s an example:

<?php
class a {
  var $test
}

$a = new a;
$a->test = 10;
echo $a->test;  // Prints 10
$b = $a->__clone();
$b->test = 12;
echo $a->text;  // Prints 12!
?>

You don’t have to explicitly declare $a->__clone(). If you omit the copy constructor in a class, PHP provides a default implementation that simply creates a new instance of the class and performs a binary copy of its member variables.

However, for those occasions when more complex cloning is required — for example, when one of your member variables cannot be replicated through a binary copy, or when some members shouldn’t be copied — you can actually implement your own version of __clone():

<?php
class myfile {
  var $f;
  function __clone() {
    $new = new myfile;
    $new->f = fopen (’myfile’, ‘r’);
  }
}
?>

Here, the copy constructor provides a clone with a new file handle.

Constructors & Destructors

PHP 5 fully implements object constructors and destructors. Again, these are improvements over PHP 4.

PHP 4 already implements constructors as functions that have the same name as the class they belong to:

<?php
class a {
  function a() {
    echo “constructor called”;
  }
}

$a = new a;  // emit “constructor called”
?>

In PHP 5, destructors are also provided, prompting the simplification of naming conventions. An object’s constructor is called __construct(), while its destructor is very imaginatively called __destruct(). For compatibility with older versions of PHP, you can still use old-style constructors, but the practice is likely to become deprecated once PHP 5 is well-established. Although destructors don’t necessarily make much sense in a web scripting language, where the lifetime of objects is rather limited and garbage collection is usually performed transparently to the script itself, destructors can come in handy if you use PHP as a general-purpose scripting platform. In this case, using destructors can be useful for conserving finite system resources (such as file or database link descriptors) in long-running scripts:

<?php
class my_file {
  var $f;
  function __construct ($filename) {
    $f = fopen ($filename, ‘r’)
  }

  function __destruct() {
    if ($f) { fclose ($f) }
  }
}
?>

Naturally, both __construct() and __destruct() can be called directly from outside your objects. This is partly necessary so you can easily propagate both constructors and destructors to parent classes (which, like in PHP4, are accessible using the special parent:: namespace).

New Constant and Variable Handling in Classes

While PHP 4 code can access all of the members of a class from the outside — in OOP parlance, all members are “public” — PHP 5 introduces qualifiers (and keywords) private, protected, and public.

* private members are only available from within the class itself.

* protected members are available from within the class and to its child classes.

* And public members are available both inside and outside the class.

Here’s an example that highlights the differences:

<?php
class a {
  private var $a;
  protected var $b;
  public var $c;
}

class b extends a {
  function b() {
    // Try accessing a protected variable
    echo $this->b;
  }
}

$a = new a;
$b = new b;
echo $a->a;  // Error: $a->$a is private
echo $a->b;  // Error: $a->b is protected.
?>

It’s possible to prevent a particular method from being overridden by a child class through the final attribute:

<?php
class a {
  final function a() {
    echo “I am final!”;
  }
}
class b extends a {
  function a() { // Error: a() is final
    echo “No, *I* am final!”;
  }
?>

In addition, PHP 5 introduces per-class constants, which can also include expressions. For example:

<?php
class my_class {
  const CLASS_CONST_1 = (10 * 5) << 1;
  const CLASS_CONST_2 = “TESTING” . “ME”;
}

// The following returns 100
echo my_class::CLASS_CONST_1;
// The following returns “TESTINGME”
echo my_class::CLASS_CONST_2;
?>

Interceptors

PHP 5 implements two special class functions called interceptors that intercept retrieve (”get”) and store (”set”) operations. These two functions, __get() and __set(), are called whenever the value of an object’s property is read or written from outside the object itself. Interceptors can implement lazy initialization techniques, and are extremely useful for creating objects that dynamically adapt their contents to a number of different factors.

For example, Listing One shows a simple class, php5_session, that provides an easy-to-use session manager.




Listing One: A PHP 5 class that uses interceptors


<?php
class php5_session {
  private $session_data;
  private $prefix;

  function __construct ($prefix)
  {
    $this->prefix = $prefix;
    // Try to get the session
    // data from the cookie
    if (isset ($_COOKIE[$prefix]))
      $this->session_data = unserialize
        (base64_decode ($_COOKIE[$prefix]));
    else
      $this->session_data = array();
  }
  function save()
  {
    // Save the session in a cookie
    setcookie ($prefix, base64_encode
      (serialize ($this->session_data)));
  }
  function __get ($key)
  {
    // Return the value in the $session_data
    return (isset ($this->session_data[$key]) ?
      $this->session_data[$key] : null);
  }
  function __set ($key, $value)
  {
    // Save the value in the $session_data array
    $this->session_data[$key] = $value;
  }
}
?>

Whenever the value of a property is retrieved or set from an instance of the php5_session class, __get() and __set() are called, allowing us to generate properties in a completely dynamic fashion.

Similar to __get() and __set(), __call() can be added to a class to intercept all attempts to call one of its member functions. While this particular feature is probably less useful than the other interceptors, it could be used, for example, to selectively allow calls to go through depending on security considerations.

Abstraction and Interfaces

As you probably know, object-oriented programming languages allow for the declaration of abstract methods and classes. These cannot be instantiated or called directly, but provide a template of sorts that provides a uniform set of interfaces, usually for overloading purposes.

Consider, for example, a simple framework that implements an HTML form. A single object could be used to describe the form itself, which could then act as a container for the individual elements. When it comes to rendering each element, however, it would be very convenient if the form could simply assume that each of the classes used to describe the individual elements would all implement a common method, say, render(), that can be used to output the HTML code needed to render the element.

At the moment, your only choice is to artificially implement this constraint by… well, remembering it. With the new Zend Engine, however, you can actually declare methods and classes as abstract, as in Listing Two.




Listing Two: An abstract class in PHP 5


<?php
abstract class form_element {
  var $value;
  var $name;
  function __construct($name) {
    $this->name = $name;
  }
  // render is an abstract function-it simply
  // acts as a placeholder that must be implemented
  // by child classes
  abstract public function render();
  function get_value() {
    $this->value = (isset ($_POST[$this->value]) ?
      $_POST[$this->value] : null);
  }
}

class text_element extends form_element {
  function render() {
    echo “<input type=text name=’{$this->name}’>”;
  }
}
?>

Because the form_element class is declared as abstract, you can’t instantiate it. However, you can subclass it. When you do, you have to (re-)define its render() method, which was declared abstract as well.

Another mechanism that provides a similar feature is the interface. An interface behaves like an abstract class that only contains abstract methods, except that a class can implement an arbitrary number of interfaces (whereas it can only extend one parent class). Here’s an example:

<?php
interface element {
  function render(); }

interface serializable {
  function serialize(); }

class text_element implements element,
  serializable {
  var $value;

  function render() {
    echo “<input type=text>”;
  }

  function serialize() {
    return $this->value;
  }
}
?>

Because a class can implement multiple interfaces, these can be used to provide multiple inheritance (MI) to your PHP scripts. MI isn’t implemented that easily — you get into some really “interesting” problems, for example when two methods from different inherited classes have the same name — so, interfaces are a generally accepted compromise.

Static Members and Variables

As you know from PHP 4, static variables are class properties that are global. If a variable is static, only one instance of the variable is created and assigned to the class’ namespace, and its value can be accessed from inside each instance of the class, as well as from the global context.

In PHP 5, it’s actually possible to assign values to static values as they’re created — not unlike what happens in Java or C++. Similarly, you can define a method as static, thereby making it accessible from outside a class’ context. Clearly, since the function is not executed within a class, the special variable $this (and the special namespace parent::) aren’t defined in its context. Here’s an example that quickly illustrates both concepts:

<?php
class a {
  static var $a;
}

class b {
  static function test() { echo a::$a; }
}

a::$a = 10;
b::test();  // Will output 10.
?>

Some Variable Magic

Another excellent new feature of PHP 5 — and one that you may have missed from other languages like C++ — is the ability to directly dereference objects that are returned by a function. In the current incarnation of PHP, this isn’t possible; you have to first assign the function’s result to a variable, and then dereference that. Here’s the current technique in PHP 4:

<?php
class a {
  var $a;

  function __construct () {
    $this->a = 10;
  }
}

class a_factory {
  function return_a() {
    return new a;
  }
}

$a = new a_factory;
$b = $a->return_a();
echo $b->a;  // Outputs 10
?>

However, in PHP5, the two operations can be combined in a single line of code — echo $a->return_a()->a;, which makes for very convenient coding.

Are You Hinting At Something?

PHP is a loosely-typed language: you cannot normally force a variable or function parameter to only accept values of a certain type. Even though PHP5 maintains this characteristic — making PHP very versatile at the expense of some performance and code clarity — it also allows you to give the scripting engine type hints for passing an object as a function parameter. Here’s an example:

<?php
class a_class {
  var $a;
  function __construct() {
    $this->value = 10;
  }
}

function test_hint (a_class $instance_of_a) {
  echo $a->a;
}
?>

As you can see, the code for test_hint() has an a_class qualifier. This indicates that the parameter $instance_of_a should be allowed if it contains an instance of a_class.

Clearly, because PHP variables are loosely typed, the interpreter checks type hints only at runtime, rather than compile time. Therefore, type hints (which only work for user-defined classes and not for PHP’s native data types) do not have the same direct benefits of a strongly-typed language: any errors caused by passing a value of the incorrect type are only be reported once you run your scripts, and then only if the flow of the program’s execution causes it to happen. This makes type hinting a bit less useful, although integrated development tools can leverage type hints to make writing object-oriented code much easier.

Improving OOP Performance

The introduction of object-oriented programming in any application framework inevitably carries with it the addition of many classes to your scripts. These, in turn, can easily cause degradation in the compilation and execution speed of each script.

PHP 5 introduces a new function called __autoload() that you can use to intercept the instantiation of a class and dynamically include any files required for that class to be recognized by the interpreter.

For example, suppose you have an include file called a.php that contains this class declaration:

<?php
class a {
  var $test;
  function __construct() {
    $a = 10;
  }
}
?>

In your main file, you can write your own __autoload() function to intercept any instantiation of a and include a.php accordingly:

<?php
function __autoload ($class_name) {
  if ($class_name === ‘a’)
    include “a.php”;
}

$a = new a;
echo $a->test;  // Will print 10
?>

Error Handling

Perhaps the second-best new feature of PHP 5 (besides improved OOP) is exception handling. If you’ve ever tried to write a proper error management system for your PHP projects, you know that PHP 4 doesn’t really provide adequate facilities. Beyond the availability of a global error handler, you’re entirely on your own, and through the years, PHP developers have had to concoct some rather creative, albeit less than optimal, solutions.

PHP 5, however, uses exceptions to trap errors in a very efficient way. An exception is an interruption of a program’s normal execution workflow, usually caused by an abnormal condition that the code is not capable of handling directly. When an exception is raised, it bubbles up, interrupting execution, working outwards until it finds code that is capable of handling it. Traditionally, you handle exceptions in a try…catch block:

<?php
class my_exception {
  var $err_msg;
  function __construct ($err_msg) {
    $this->err_msg = $err_msg; }
}

try {
  if (!mysql_connect (’my.server.com’))
    throw new my_exception
      (’Cannot connect to server’);
} catch (my_exception $e) {
  die (”Exception caught: {$e->err_msg}”);
}
?>

In a try…catch block, the code inside the try{} block is executed, and if an error occurs anywhere in that code, you have the option of throwing an exception and trapping it later in the catch{} block.

The great advantage of exception handling is that a single exception handler can easily manage all the errors that occur in a large block of code, making your code much less cluttered (and inherently safer if you use this mechanism consistently) and your scripts much shorter.

New Data Management Tools

MySQL is currently the most widely-used database management system for PHP projects. However, recent changes in MySQL’s licensing policies have forced the PHP development team to remove the bundled MySQL library from the default PHP source tarball, making it just slightly more difficult to effectively support the latest versions of the DBMS. While this doesn’t mean that you can’t use MySQL with PHP, the changes in MySQL’s library license dictate that you must obtain a commercial license from MySQL AB if you want to use it in a commercial application.

Luckily, the PHP team has introduced an extension based on SQLite, a file-based, embeddable database management system. SQLite is significantly less powerful than MySQL. Possibly its biggest drawback is that it only supports database-wide locks, meaning that only one thread can write to a database at any given time. But, for simpler applications, SQLite could provide a “quick and dirty” alternative to MySQL that doesn’t require the installation of additional software, and works right out of the box.

Incompatibilities Between PHP 4 and PHP 5

Strictly speaking, a good 80-95% of your existing PHP code will work just fine if you switch over to PHP 5. In fact, if you don’t use OOP and your code doesn’t include functions that share their names with the new reserved words introduced by PHP 5 (such as private, public, throw, and so forth), it will probably execute just fine — with the added bonus that PHP 5 is quite a bit faster than its older cousins.

If you use object-oriented programming techniques, whether your application works or not depends largely on how disciplined you’ve been in your coding. If you rely on some of PHP’s quirks, such as considering objects as nothing more than scalar types to perform your tasks, then you may encounter some problems. If, however, you played it completely straight — ignoring PHP’s deficiencies and overcoming them using traditional mechanisms, such as passing objects by reference — you should be fine, and again enjoy slightly better performance.

So, When Should You Switch?

With a final version still several months away, it’s too early to say when, or even whether, you should switch to PHP 5. In most cases, switching to the new version of the platform is likely to be a gradual process, and your first steps should be dedicated exclusively to learning the new features that PHP 5 has to offer. There’s plenty of new concepts and techniques to get acquainted with, particularly if you plan to work with objects.

Perhaps the best thing that you can do at this point is to open your browser, point it to the PHP web site at http://www.php.net, download a current version of PHP 5, and start testing it. While you plan how to best move and port your software to it, you may just as well also help the PHP team identify and correct any remaining bugs!



Marco Tabini is the publisher of php|Architect magazine, and is the author of the forthcoming book Advanced PHP 5, to be published by Apress. You can reach Marco at marcot@tabini.ca.

Comments on In With the New PHP

No comments yet.

Sorry, the comment form is closed at this time.

Free Email Newsletters
Linux Mag Weekly
Blade & Virtualization
Making the Most of Multicore
HPC Weekly
Linux Magazine Case Study Update
Linux Magazine Webinar Update
Linux Magazine White Paper Update
Linux Magazine PR Daily
Email Address:

Sponsored Links