Page 1 of 1

implementing named parameters & automatic accessors [SOLVED]

Posted: Wed Sep 10, 2008 1:26 am
by opensas
hi everybody

I'm giving my first steps with php, and I was trying to implement a few things I find pretty useful in asp (ok, it's mainly ruby inspired stuff, actually)...

I wanted to implement named parameters, using an associative array to access the actual the properties of the object

and i wanted automatic accessors to behave like this:

by default every propery is read/write

if I define some getter / setter method, then execute it, otherwise access directly the variable.

well, i managed to achieve all this... this is how (please, any opinion / advice is welcome!)

Code: Select all

 
 
class my_class {
 
  private $_name = 'unknown';
  private $_surname = 'unknown';
 
  public function get_surname_and_name() {
    return $this->surname . ', ' . $this->name;
  }
 
  public function set_surname_and_name( $value ) {
    $parsed_value = explode( ', ', $value );
    
    $this->surname = isset( $parsed_value[0] ) ? $parsed_value[0] : 'unknown';
    $this->name = isset( $parsed_value[1] ) ? $parsed_value[1] : 'unknown';
  }
  
  public function __construct( $members = null ) {
    if ( ! is_null( $members ) ) $this->set_members( $members );
  }
 
  public function __destruct() {
  }
  
  public function set_member( $member, $value ) {
    eval( '$this->' . $member . ' = ' . var_export( $value, true ) . ';' );
  }
 
  public function set_members( $members ) {
    foreach( $members as $member => $value ) {
      $this->set_member( $member, $value );
    }
  }
  
  public function __set( $name, $value ) {
    // si existe el setter lo ejecuto
    if (method_exists( $this, 'set_'.$name ) ) {
      $this->{'set_'.$name}( $value ); return;
    }
    //si existe la propiedad la modifico
    if (property_exists( get_class( $this ), '_'.$name ) ) {
      $this->{'_'.$name} = $value; return;
    }
    // error
    throw new exception( "No 'set_$name' setter method nor '_$name' private/protected property found." );
  }
  
  public function __get( $name ) {
 
     // if the getter exists, execute it
    if (method_exists( $this, 'get_'.$name ) ) {
      return $this->{'get_'.$name}();
    }
 
    if (property_exists( get_class( $this ), '_'.$name ) ) {
      return $this->{'_'.$name};
    }
    // error
    throw new exception( "No 'get_$name' getter method nor '_$name' private/protected property found." );
  }
  
}
 
$c = new my_class( array( 
    name      => 'Juan',
    surname   => 'Gutierrez'
  ) );
 
echo '$c->surname_and_name: '.$c->surname_and_name.'<br/>';
 
$c->surname_and_name = 'de la Serna, Federico';
 
echo '$c->surname_and_name: '.$c->surname_and_name.'<br/>';
 
echo '$c->name: '.$c->name.'<br/>';
 
echo '$c->surname: '.$c->surname.'<br/>';
 
 
this code correctly outputs:
$c->surname_and_name: Gutierrez, Juan
$c->surname_and_name: de la Serna, Federico
$c->name: Federico
$c->surname: de la Serna
the problem is that i'd like to have all this behaviour in a base class, something like base_object, so that all of my clases can extend it, and inherit all this stuff...

so I created a base_object class with the following methods: __construct, __destruct, set_member, set_members, __set and __get

then I defined my_class2 which extended base_object

this is my new "my_class"

Code: Select all

 
require 'base.php';
 
class my_class extends base_object {
 
  private $_name = 'unknown';
  private $_surname = 'unknown';
 
  public function get_surname_and_name() {
    return $this->surname . ', ' . $this->name;
  }
 
  public function set_surname_and_name( $value ) {
    $parsed_value = explode( ', ', $value );
    
    $this->surname = isset( $parsed_value[0] ) ? $parsed_value[0] : 'unknown';
    $this->name = isset( $parsed_value[1] ) ? $parsed_value[1] : 'unknown';
  }
  
  public function __construct( $members = null ) {
    parent::__construct($members);
  }
 
  public function __destruct() {
    parent::__destruct();
  }
  
}
 
$c = new my_class( array( 
    name      => 'Juan',
    surname   => 'Gutierrez'
  ) );
 
echo '$c->surname_and_name: '.$c->surname_and_name.'<br/>';
 
$c->surname_and_name = 'de la Serna, Federico';
 
echo '$c->surname_and_name: '.$c->surname_and_name.'<br/>';
 
echo '$c->name: '.$c->name.'<br/>';
 
echo '$c->surname: '.$c->surname.'<br/>';
 
you see, it's basically the same whithout the stuff it should be inheriting...

but then I get the following error:
Fatal error: Uncaught exception 'Exception' with message 'No 'set_name' setter method nor '_name' private/protected property found.' in C:\Inetpub\wwwroot\urbanistik\lib\cls\experiment\base.php:32 Stack trace: #0 C:\Inetpub\wwwroot\urbanistik\lib\cls\experiment\base.php(13) : eval()'d code(1): base_object->__set('name', 'Juan') #1 C:\Inetpub\wwwroot\urbanistik\lib\cls\experiment\base.php(13): eval() #2 C:\Inetpub\wwwroot\urbanistik\lib\cls\experiment\base.php(18): base_object->set_member('name', 'Juan') #3 C:\Inetpub\wwwroot\urbanistik\lib\cls\experiment\base.php(6): base_object->set_members(Array) #4 C:\Inetpub\wwwroot\urbanistik\lib\cls\experiment\accessor_test_2.php(22): base_object->__construct(Array) #5 C:\Inetpub\wwwroot\urbanistik\lib\cls\experiment\accessor_test_2.php(34): my_class->__construct(Array) #6 {main} thrown in C:\Inetpub\wwwroot\urbanistik\lib\cls\experiment\base.php on line 32
 
so, it seems like $this cannot access the private $_name variable from base_object... but, should it run just as if it were defined in class my_class??? isn't that what inheritance is about??

it seems like $this variable cannot access any of "my_class" methods or properties, its context seem to be tied to "base_object"

am I missing something???

thanks a lot

saludos

sas

Re: implementing named parameters & automatic accessors

Posted: Wed Sep 10, 2008 1:46 am
by Christopher
I did not look to carefully, but you probably need to make your properties protected rather than private.

Re: implementing named parameters & automatic accessors

Posted: Wed Sep 10, 2008 12:43 pm
by opensas
right now I can't give it a try, but is sounds promissing, I've just checked the documentation (yes, I know, RTFM) http://ar.php.net/manual/en/language.oo ... bility.php

and it says:
Protected limits access to inherited and parent classes (and to the class that defines the item).
thanks a lot... I'll tell you how it goes...

Re: implementing named parameters & automatic accessors

Posted: Thu Sep 11, 2008 8:24 pm
by opensas
hey!!!

it worked like a charm

thanks a lot...