tags:

views:

5010

answers:

7

I got this class:

Class Username {
protected $id;
protected $username;
protected $contact_information;

     private __construct($id) {
       $this->id = (int) $id; // Forces it to be a string
       $contact_information = new ContactInformation($this->id);
     }
}

Class ContactInformation extends Username {
    protected $mobile;
    protected $email;
    protected $nextel_id;
    .....
}

My problem is: I want to access the $id and $username (and lots of other variables) on ContactInformation, but parent:: or $this-> does NOT work, looks like everytime i do "new ContactInformation....) PHP creates a "new Username". Any chance to access the CURRENT values from Username?

Thanks

+6  A: 

Why is the Username constructor private? If you mean to make it impossible to create a Username, make the Username class abstract. Also, do NOT make a new contact information from the parent class. Here's another way to put it:

abstract class Username {
   protected $id;
   protected $username;

   public __construct($id) {
      $this->id = (int) $id; // Forces it to be a string
   }
}

class ContactInformation extends Username {
    protected $mobile;
    protected $email;
    protected $nextel_id;
    public __construct($id, $mobile, $email, $nextel_id) {
       parent::__construct($id)
       $this->mobile = $mobile;
       ....
    }
}

Now, instead of instantiating the Username directly (which is now impossible), you instead create a ContactInformation. ContactInformation then calls the Username constructor in its own constructor.

PatrikAkerstrand
Declaring a protected constructor is common in singletons. But you're probably right about using abstract in this case, so you'd get more useful errors if you tried to create a new Username();
James Socol
Yes, it is true that it is common in the Singleton-pattern. But the Singleton-pattern is not great to use when you need to extend the Singleton-class, especially not in PHP. A lot of people also argue that the Singleton-pattern is flawed, and that it is better to ensure that, instead of forcing a single instance programmatically, only a single instance is created in the application.Also, if he wants to follow the Singleton-pattern he will need a "getInstance"-method and also to make the __clone-magic method private.
PatrikAkerstrand
I don't think James was suggesting that Singleton is applicable here; he was pointing out that a private or protected constructor has valid uses.
Rob
+1  A: 

The parent:: method is only used to access parent methods that you have overridden in your subclass, or static variables like:

class Base
{
    protected static $me;

    public function __construct ()
    {
        self::$me = 'the base';
    }

    public function who() {
        echo self::$me;
    }
}

class Child extends Base
{
    protected static $me;

    public function __construct ()
    {
        parent::__construct();
        self::$me = 'the child extends '.parent::$me;
    }

    // until PHP 5.3, will need to redeclare this
    public function who() {
        echo self::$me;
    }
}

$objA = new Base;
$objA->who(); // "the base"

$objB = new Child;
$objB->who(); // "the child extends the base"

You probably want a proper subclass. Don't create a subclass in the constructor of the base class, that turns all sorts of OOP best-practices upside down (loose coupling, etc) while also creating an infinite loop. (new ContactInformation() calls the Username constructor which creates a new ContactInformation() which...).

If you want a subclass, something like this:

/**
 * Stores basic user information
 */
class User
{
    protected $id;
    protected $username;

    // You could make this protected if you only wanted
    // the subclasses to be instantiated
    public function __construct ( $id )
    {
        $this->id = (int)$id; // cast to INT, not string

        // probably find the username, right?
    }
}

/**
 * Access to a user's contact information
 */
class ContactInformation extends User
{
    protected $mobile;
    protected $email;
    protected $nextel;

    // We're overriding the constructor...
    public function __construct ( $id )
    {
        // ... so we need to call the parent's
        // constructor.
        parent::__construct($id);

        // fetch the additional contact information
    }
}

Or you could use a delegate, but then the ContactInformation methods wouldn't have direct access to the Username properties.

class Username
{
    protected $id;
    protected $contact_information;

    public function __construct($id)
    {
        $this->id = (int)$id;
        $this->contact_information = new ContactInformation($this->id);
    }
}

class ContactInformation // no inheritance here!
{
    protected $user_id;
    protected $mobile;

    public function __construct($id)
    {
        $this->user_id = (int)$id;
        // and so on
    }
}
James Socol
A: 

Fatal error: Undefined class constant 'id' in D:\Test\lib\ClassCompromisso.php on line 236

Still doesnt work using static.

Well i'll just post my current class as i was just using an example:

class Task {
    protected $id;
    protected $date;
    protected $time;
    protected $duracao;
    protected $local;
    protected $usuario;
    protected $pessoa;
    protected $participantes;
    protected $equipamento;
    protected $restrito;

    public function Task($id) {
     $this->id = (int) $id;  
     $this->equipamento = new Equipment($id);
    }

class Equipment extends Task {
    private $equipment_id = array();
    private $equipment_name = array();
    private $equipment_obs = array();

    public function Equipamento($id) {
         (here i want to use the values of my parent object. tried with static, $this->, parent:: and nothing works. I also have more child class wich need access to the current values of the parent class).
        }

Hints?

A: 

If I understand you correctly, you want to access properties of an object from an object contained in that object? If this is correct, here's how its done:

class A {

  // These are the properties you want to access from the child object
  public $property_a;
  public $property_b;
  public $property_c;

  // This is the child object variable
  public $child_object;

  public function __construct( ) {

    // Pass 'this' into the child so that the child has a reference back to the parent
    $this->child_object = new B($this);
  }
}

class B {

  // Holds a reference to the parent object
  protected $parent_object;

  public function __construct( $object ) {

    // Remember the reference to the parent object
    $this->parent_object = $object;
  }

  // Just a Demonstration Method
  public print_parent_property_a()
  {
    // Reach into the referred parent object, and get it's property
    print $this->parent_object->property_a;
  }
}

So if you were to do:

$my_object = new A();
$my_object->property_a = 'test_value';
$my_object->child_object->print_parent_property_a();

You'd get 'test_value'

It's slightly different from your example, in that you'll need the parent class properties to be public so that the child can access them.

This all works because in PHP, objects are always passed by reference unless you explicity clone them.

Jonathan Hanson
You've used both composition and inheritance in this case; the latter is unnecessary. Can you clarify your example?
Rob
A: 

First, when you create a ContactInformation, it is also contains all the non-private properties and methods of Username. You do not need a separate Username instance.

Class Username {
    protected $id;
    protected $username;

    protected __construct($id) {
        $this->id = (int) $id; // Forces it to be a string
    }
}

Class ContactInformation extends Username {
    protected $mobile;
    protected $email;
    protected $nextel_id;
    // Pretend that these are here because they're defined in my parent
    //protected $id;
    //protected $username;

    public __construct($id) {
        parent::__construct($id);
        echo $this->id; //Should echo 1
    }
}

However, since all the fields are protected, this isn't going to work:

$contact_information = new ContactInformation(1); // Works fine
echo $contact_information->id;
// Whoops, visibility error because id isn't public
R. Bemrose
A: 

Maybe I wasnt clear?

What i want is: access the members from the Parent Class on the Child class (thats include the variables). I do need to query some stuff and I need to access all the properties from the Parent class (and their current values) in order to make my class work as expected. Also I have some other classes that derives from the Parent class.

A: 

Jonathan got my point and it's working correctly.I want to do exactly what jonathan just explained (and it works), but maybe theres a better way to do this?