I don't use PHP5 since most of my code is deployed on servers only running PHP4, so I don't know if there is a function like this in PHP5. My goal was to make a bless() function similar to perl's because I am really lazy and don't like to deal w/ constructors that take lots of arguments. Often times I have an array w/ all the values that can map to instance variables for the class, and a bless($array, $class) would be handy. For example, I just got a row from a table in a database and that row is basically all the instance vars for an object. I haven't tried it for composite objects (objects that contain objects), so its just for simple object graphs. Its in use on a production site so it seems to work ok. Requires PHP 4.2 or later (uses get_class_vars() ).

Let me know what you think or problems you find.

function bless( &$arr, $class ){

// TODO add check version of PHP?

// make sure the php file defining $class is included already!
if( !class_exists($class)){
    trigger_error( "Undefined class $class", E_USER_WARNING );
    return;
}

// will be an assoc array of instance var names as keys and NULL for all values
// requires PHP >=4.2 to work right
$inst_vars = get_class_vars( $class );
foreach( $arr as $i=>$v ){
    $inst_vars[$i]= $v;
}

// the serialized version of an object in PHP 4 looks similar to serialized array
// so get the serialized version of the array first
$serialized = serialize( $inst_vars );
$serialized = preg_replace( "/^a\:\d+\:/", '', $serialized );

// now add what we need to make this look like serialized object
$serialized = 'O:' . strlen($class) .':"'. strtolower($class) .'":'. count($inst_vars) .':'. $serialized;

// try to unserialize and check if value is FALSE
$obj = unserialize( $serialized );
if( $obj === false ){
    trigger_error( "Unable to bless into $class", E_USER_WARNING );
    return null;
}

return $obj;
}

    Did you know that PHP class properties don't have to be declared, they can be written dynamically? I've written simple bind functions which map an array to a value object (below), although this does check if a property exists first. Admittedly you would have to add this to every constructor whereas your function can be used for any class. How would you deal with public/private/protected properties though?

    public function __construct( $array )
    {
      foreach( $array as $key => $value )
      {
        if( property_exists( $key, $this))
        {
          $this->$key = $value
        }
      }
    }
    

      Shrike,
      I like your sugggestions and I thought about adding a 'from array' constructor, like your __construct(). In fact, its a superior solution. As for public, private, etc, I didn't care :eek: .

      Typically the class that is calling bless() is rather intimately related to the object anyway. For example, data-access layer class that talks to DB or whatever datasource is and has to instantiate objects in the domain layer:

      $user_gateway = new UserGateway( $db_connection, $user_table );
      $user = $user_gateway -> find( $id );
      

      Typically the gateway does a query on a db, gets a row then has to instantiate the object---thats where I figured I could use bless($row, 'User').

      construct() is better especially since it doesn't depend on how PHP serializes objects, which I suspect could change in the future. Also I suspect construct() would work fine for composite objects.

      Thanks!

        I actually deleted my post because PHP 4 doesn't have the property_exists() function. You can write the function without checking if the property exists first if you don't mind creating a property for every array index. So in PHP 4 your function has an advantage.

          Write a Reply...