Last updated November 1, 2012. Created by fago on December 23, 2009.
Edited by gollyg, mitchell, technicalknockout, tizzo. Log in to edit this page.

Preliminary Warning:
"If you're afraid of classes and objects in PHP, run away now." - jpetso.

The Extendable Object Faces API allows modules to extend your objects. It basically implements the Facade pattern in a modular way.

Overview

A module that wants to extend an object may only do so on top of a defined interface, preventing uncontrolled growing objects. Thus one can write some code, define an interface for it and attach it to potentially any extendable object out there. Other modules have an easy way to test whether some object has a functionality in place by checking for the availability of a certain interface. As each module can extend the objects, it's important to prevent method name collisions by using safe method names, best prefix the method names with the providing module's name.

Shipping with the API

Note that using the API doesn't introduce a dependency as you can just ship your module with the faces.inc provided. Read the README for instructions how to do so.

Using the API

So let's make a class extendable. For that just inherit from FacesExtendable.

<?php
/**
* Extendable Class
*/
class FacesTestElement extends FacesExtendable {
   public
$name;
 
//Your code here..
}
?>

Then define an interface to use for extending it. Let's use an extender class to implement it:

<?php
interface FacesTestInterface {
  function
xmlExport($namespace);
}
/**
* Extender Class
*/
class FacesTestExtender extends FacesExtender implements FacesTestInterface {
  function
xmlExport($namespace) {
    echo
$this->object->name;
    
// add code...
 
}
}
?>

Extender classes should inherit from FacesExtender or just implement the simple FacesExtenderInterface themself. The extender gets a reference on the extended object during construction which is usually saved to $this->object. Of course one can override the constructor to use a more meaningful variable name.
For accessing protected or private properties and methods of the extendable one can use the call() and property() methods provided.

That's it. Now you can use the face!

<?php
    $element
= new FacesTestElement();
   
$element->name = 'test';
   
$element->extendByClass(array('FacesTestInterface'), 'FacesTestExtender');
   
// Now use it.
   
print $element->xmlExport('http://drupal.org/project/faces/example');
?>

So let's show how you could specify a function living in the include file 'xml.inc' of your 'your_module'.

<?php
    $element
= new FacesTestElement();
   
$element->name = 'test';
   
$include_file = array('module' => 'your_module', 'name' => 'xml');
   
$element->extend('FacesTestInterface', array('xmlExport' => 'your_module_the_function'), $include_file);
   
// Now use it.
   
print $element->xmlExport('http://drupal.org/project/faces/example');
?>

That's it. The function always gets a reference on the object and the method's name appended to the used arguments. So you can declare it in your xml.inc file like that:

<?php
function your_module_the_function($namespace, $object) {
//code..
}
?>

Faces will include that file for you upon method invocation, so you don't have to care about that yourself.
For classes, you can use the same inclusion mechanism, however for drupal 7 you may want to rely on the code registry for that instead.

To check whether a object implements a certain interface using faces, you may use

<?php
  $object
->facesAs('yourInterface');
?>

You can find more examples in the simpletests of the module. If you are worried about the performance, checkout this benchmarks.

How do modules play with that?

You may wonder how modules should be able to extend the object with the API described above. Well modules just need a reference on the object, then they are able to extend it. A simple way to pass your object around is using a hook, e.g. the entity API objects can be easily extended during the entity's hook_entity_load(). But also modules may implement own extension mechanisms like the rules modules which implements its own hook_rules_plugin_info() where extenders may be defined.

Looking for support? Visit the Drupal.org forums, or join #drupal-support in IRC.