views:

145

answers:

7

Hello,

First of all, I do not want to extend a class. I would ideally like to do this.

public function __construct() {
 /* Set Framework Variable */
 global $Five;
 $this =& $Five;
}

I have a system where the variable $Five is a container class which contains other libraries. I could assign this to a local variable of Five... i.e.

public function __construct() {
 /* Set Framework Variable */
 global $Five;
 $this->Five = $Five;
}

However, the reason why I am trying to avoid this is that function calls would be getting a little long.

$this->Five->load->library('library_name');

Its a little ugly. Far better would be.

$this->load->library('library_name');

What is the best solution for this?

+2  A: 

$this is a reference to the current instance of the class you are defining. I do not believe you can assign to it. If Five is a global you ought to be able to just do this:

$Five->load->library('library_name');
Daniel Bingham
@JasonS: And if it was possible how would you call your application object?
LukeP
+5  A: 

I think that

$this->Five->load->library('library_name');

is going to be your best option unless you decide to have the class extend the helper class. AKA

class Something extends Helper_Class

However, this means that Helper_Class is instantiated every time you instantiate a class.


Another method would be to have a pseudo-static class that assigned all of the helper classes to class members

public function setGlobals($five)
{
    $this->loader = $five->loader;
}

Then just call it

public function __construct($five)
{
    someClass::setGlobals($five);
}

If $Five is a global, you could just global $Five everytime you want to use it, but putting that at the top of every function just seems like bad coding.


Also, I'd just like to do my public service announcement that Global variables are generally a bad idea, and you might want to search 'Dependency Injection' or alternative to globals. AKA

public function __construct($five);

instead of

global $five;

Globals rely on an outside variable to be present and already set, while dependency injection requests a variable that it is assuming to be an instance of the Five class.

If you are running PHP 5.1 (Thanks Gordon), you can insure the variable is an instance of the FiveClass by doing this:

public function__construct(FiveClass $five);
Chacha102
Type Hints also work with PHP < 5.3
Gordon
Ah... wasn't sure which version it was, so I assumed it was 5.3.
Chacha102
Found it for you: *Type Hints can only be of the object and array (since PHP 5.1) type.* See http://de3.php.net/manual/en/language.oop5.typehinting.php
Gordon
+1  A: 

You might wanna go with some kind of implementation of the dependency injection pattern:

Dependency injection (DI) in computer programming refers to the process of supplying an external dependency to a software component. It is a specific form of inversion of control where the concern being inverted is the process of obtaining the needed dependency.

See also the documentation for the symfony DI container. I can highly recommend this DI container implementation if you want to improve the way you handle your 'globals'.

You could also have a read of this question on 'best ways to access global objects'.

phidah
A: 

I'm pretty sure you can't reassign $this, as it's one of those special things that looks like a variable in PHP, but is treated slightly differently behind the scenes.

If your concerns are the semantics of your method calling getting too long, I'd make load a method call instead of an object property

$this->load()->library('library_name');

public function load()
{
    return $this->Five;
}
Alan Storm
Looks hackish to me, but if you do use thi way, you might want to look at a helper class that the main class that does logic would extend.
Chacha102
Yeah, well, the OP was assigning a global to an internal property, so the whole thing smelled hackish without a total restructure, which went beyond the scope of the question.
Alan Storm
A: 

How about making the relevant data members and methods of Five static class members? This

$this->Five->load->library('library_name');

would become this

Five::load->library('library_name');

and you wouldn't have to pass &$Five around everywhere.

Chris
No, you'd have to hardcode the calls to Five into your classes then. It's better to favor aggregation over composition and to inject dependencies, instead of creating the objects inside the class or hardcoding static calls into them. This let's you more easily swap them out, e.g. with Mocks in UnitTests.
Gordon
+1  A: 

You cannot overwrite $this (like e.g. in C++) but you can easily build an aggregate using __call() for method calls and __get(), __set(), __isset() for properties.

Example for __call():

class Five {
  public function bar() {
    echo __METHOD__, " invoked\n";
  }
}

class Foo {
  protected $Five = null;

  public function __construct(Five $five=null) {
     if ( is_object($five) ) {
       $this->Five = $five;
     }
   }

  public function __call($name, $args) {
    // there's no accessible method {$name} in the call context
    // let's see if there is one for the object stored in $five
    // and if there is, call it.
    $ctx = array($this->Five, $name);
    if ( !is_null($this->Five) && is_callable($ctx) ) {
      return call_user_func_array($ctx, $args);
    }
    else {
      // ....
    }
  }
}

$foo = new Foo(new Five);
$foo->bar();

prints Five::bar invoked.
In my opinion the biggest draw back is that it is much harder to see "from the outside" what the object is capable of.

VolkerK
The way it is now, it has no clear identity. Imagine Foo was Log and you pass it a User object, just because you can. What would you expect $log->delete to do? You could get around this by coding against an interface and limit what Foo accepts as object.
Gordon
Ok, added a type hint. Could be an interface as well. Basic idea stays the same.
VolkerK
A: 

maybe better for you will be to use PHP Magic Methods? http://www.php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.methods

tomaszsobczak