tags:

views:

140

answers:

5

Hello people, I have a problem here, which I have been thinking about for the past few days. In a php application to do something with a object you need to:

  1. define it
  2. run a function with it like so: (with autoloading, and a registry object)
  3. $registry->obj = new mathClass($var1,$var2); //creates object where $var1 holds the a database object, and $var2 holds the value 1 for example
  4. $registry->obj->calculate('value'); //fetches product rows and returns their total value. This way at any time in the script i can simply run the calculate function (or some other function) that I defined beforehand.

Imagine a web application that has hundreds of classes that might or might not be required for this specific page load, but can only be defined at the start of the application. The desired solution is that I simply run

$obj->calculate('price'); 

without creating the object, for example like this

mathclass::calculate('price'); 

this then autoloads the mathclass as required without having the principal overhead, the problem here is that I can no longer give the mathclass any variables at the start

($var1,$var2).

What I want is to be able to pseudo-create the object without any autoloading of the class happening, as to not add the overhead, but that the object creates itself with the variables but only when I actually need to do something with it.

I mean does php really expect me to define each and every class at the start so that I can later use them? is this Lazy-loading? Eager loading?

I might be explaining this badly so please point me in the right direction.

+1  A: 

if you use the autoload functionality it will only load the math class when you instantiate it, 1 option is to instantiate it when you need it, another option is to use some kind of wrapper class that will include and call the class.

Xeross
how to predefine the way the class loads the other class before it is loaded?
YuriKolovsky
You'd have to make a wrapper class specifically for that class (or some extendable class). Make it check if the class is instantiated as a member variable, if not require_once and instantiate. Note this solution sounds sub-optimal to me.
Xeross
agreed, it's one of the things I also encountered.
YuriKolovsky
A: 

What you can use is Static classes in PHP. Although this is something you might consider not doing for high-traffic websites.

Declare a class like so:

class Something
{
    private static $var = "something";

    public static function PrintVar()
    {
        echo self::$var;
    }
}

Now you can include this class and execute the code anywhere you like without initializing the object.

Like so:

Something::PrintVar();

prints

something

Good luck!

Stephen
thanks for the luck, but static classes is not what I'm looking for because you still have to load them beforehand even if you're not going to use them.
YuriKolovsky
A: 

Part of the reason why class objects require defining using new() is because they consume memory. Normally PHP will perform memory cleanup at the end of script if you havent done so, but usually in a constructor/destructor object-oriented environment you would want to unset() that class object to free up memory. Earlier versions of PHP (before php4) had issues with memory leaks due to these reasons.

If you want to avoid the whole initialization process you may just want to try a simple include library, such as this:

<?
if (!function_exists("calculate"))
 {
 function calculate($var1={default},$var2={default}) 
   {
   ...routine...
   }
 }
?>

And then you do not have to deal with the whole pain of defining a full class for a simple routine.

Talvi Watia
+2  A: 

Use a Dependency Injection Framework. It lets you configure your classes from config files and when you need a class you simply call it through the service builder.

Gordon
excellent read, where do you keep finding these Gordon.but how does it does not solve my problem! (im probably to blame here with my explanation)
YuriKolovsky
@Yuri you find most of these at articles at http://planet-php.org. I am sorry, but I didnt get the remainder of your comment. Did you mean, it helped solve the problem or it didnt? If not, what part do you need help with?
Gordon
thanks Gordon for the offer to help, i REALLY appreciate it.The problem i'm encountering is better described here:http://stackoverflow.com/questions/3346932/php-efficiently-running-functions-with-one-time-loaded-classes-multiple-times-inthe question is: how to lazy-load dependent classes.
YuriKolovsky
@Yuri if you use a DI Container, you configure how classes should be instantiated. When you need need them, you simply tell the container to get a specific class and the container will then instantiate it for you. That's pretty much lazy loading. It's very similar to @dbemerlin's solution.
Gordon
sorry Gordon, I really want to understand how dependency injection helps with lazy-loading and how to configure how a class should be instantiated, could you explain with a bit more detail?
YuriKolovsky
@Yuri dont know what to tell you apart from what is explained in http://components.symfony-project.org/dependency-injection/ and http://fabien.potencier.org/article/15/symfony-service-container-using-xml-or-yaml-to-describe-services already. It's pretty obvious, isnt it? You configure the class and when you need it, the DI container will create it for you like you configured it.
Gordon
oh, the article was a series! I only read the first page and thought that was it and that the links at the start were in-page-links.It all makes sense now!
YuriKolovsky
+1  A: 

You can use a lazy loading factory, i.e.

class Registry
{
  private $registeredClasses;
  private $loadedClasses;
  private $objects;

  public function RegisterClass($className, array $parameters)
  {
    // ... store class ...
  }

  private function Load($className)
  {
     // Load the class via some sort of autoloader
  }

  private function CreateInstance($className)
  {
    $parameters = $this->GetParametersFor($className);
    $this->CreateNewInstanceWithParameters($className, $parameters);
  }

  public function GetObject($className)
  {
     if (!$this->IsAvailable($className))
     {
       $this->Load($className);
       $this->CreateInstance($className);
     }
     return $this->GetInstanceOf($className);
  }
}

Later in your code you use it like this:

$registry = new Registry();
$registry->RegisterClass("math", array("var1" => $var1, "var2" => $var2));
...

$registry->GetObject("math")->calculate($x1, $x2);
...

Ofc you need to add the parts i was too lazy to add, i.e. the autoloading.

dbemerlin
That's more like a [ServiceLocator](http://martinfowler.com/articles/injection.html#UsingAServiceLocator) than a Registry, isnt it?
Gordon
It's mostly a mix of both. I called it Registry because the Question seemed to use a Registry and (depending on the implementation and use) Registrys and ServiceLocators are quite related.
dbemerlin
True, it's a registry with added capability to build services. Just felt the Service Locator pattern would be a more appropriate class name since it's not "just" a Registry.
Gordon
This is the closest to a solution, I'm still thinking my problem through so bear with me.
YuriKolovsky
this is essentially the same answer as Gordon's, but without a explanation of how this should be used.in the end, what I will use will be A. load main config file B. config file imports class starting options C. I call class and it loads as needed, too bad there's no 2 best answers button's.
YuriKolovsky