1

I am making an MVC application. I made this function in my loader class:

public function load_models($model)
{
    if ($model) {
        set_include_path($this->modelDirectoryPath);
        spl_autoload_extensions('.php');
        spl_autoload($model);   
    }
}    

I'm using this function from my controller like this:

$this->load->load_models('news');

I want to access this model class like this:

$this->load->news->get_article();

But I can't unless I do this:

$this->load->news = new news();
$this->load->news->get_article();

I want to access it without typing $this->load->news = new news();. I also want it to be automatically instantiated. Can anyone help?

tereško
  • 58,060
  • 25
  • 98
  • 150
  • Make `news` a private or otherwise inaccessible property of the `load` object, and define a `__set()` and `__get()` method which will instantiate the object if one does not yet exist. Although to be honest you're just moving the same code somewhere else in your scripts and it doesn't make much difference. – DaveRandom Jun 18 '12 at 21:13
  • the 'news' is a class model !!! –  Jun 18 '12 at 21:15
  • What's to stop you defining a magic method that does `public function __get($name) { if (!isset($this->privateArray[$name])) { $this->privateArray[$name] = new $name(); } return $this->privateArray[$name]; }` ? – DaveRandom Jun 18 '12 at 21:21
  • thank you daveRandom very much it's worked with this public function __get($name) { if (!isset($this->$name)) { $this->$name = new $name(); } return $this->$name; } –  Jun 18 '12 at 21:33

2 Answers2

1

Make get_article() a static method and access it like this:

$this->load->news::get_article();

You cannot access non-static methods without instantiating at least one instance of the class. Even with reflection, you can't actually call and regular method.

You could implement a magic method in the load class that when you access any property such as

$this->load->news->get_article();

it checks to see if the 'news' property's name is also loaded a classname and if it is but it's not set to an instance of the class, create one and assign it to it.

This is the magic method:

public function __get(){ ... } ; 

Basically, this magic method always gets called every time you access an object's ...every time you access an object's inaccesible properties (ones not declared or created)

Ray
  • 40,256
  • 21
  • 101
  • 138
  • i want to access the whole class functions this is just an example – Hmmm Jun 18 '12 at 21:11
  • @user1464822 read the updated answer and see if my solution is clear – Ray Jun 18 '12 at 21:20
  • please understand i don't want to make the model 'news' as a property for the load class i want to make it a property for the controller so i could write this $this->news->get_article(); – Hmmm Jun 18 '12 at 21:21
  • 1
    ...`every time you access an object's` *inaccesible* `properties`... ;-) – DaveRandom Jun 18 '12 at 21:22
  • @user1464822 Assuming the controller is a class and you have an instance of it, add the magic method to the controller. – Ray Jun 18 '12 at 21:22
  • @user1464822 `__get()` works internally as well, as long as the property you are referencing doesn't exist. So you can have an associative array that you use to maintain name to object relationships and it will work (see my comment above) – DaveRandom Jun 18 '12 at 21:24
  • @DaveRandom Good note... yes, you'll not want to define the property in the controller class, only add it if it's missing. – Ray Jun 18 '12 at 21:25
  • thank DaveRandom very much it worked with this public function __get($name) { if (!isset($this->$name)) { $this->$name = new $name(); } return $this->$name; } – Hmmm Jun 18 '12 at 21:31
1

You seem to be "channeling" something of CodeIgniter, which is severely outdated (if you want to know details, go to PHP chat room). That would not be the framework to emulate, if you want high quality code.

Oh, and the pattern you are implementing is actually MVP, not MVC .. there is a difference.

  • At first you should so is make autoloader, which actually works. Read about spl_autoload_register() .. how it is used, what it actually does. If you need some examples, beside the ones provided in comments, you can look up implementations of PSR-0. It should give you some idea, how to use it in practice.

    This all would basically get rid of your $this->load->load_models('news'); line in controller.

  • in MVC the Model is a layer not an object/class. I don't intend to repeat whole song and dance, i wrote an answer on this some time ago .. it's long =/

  • you should not use new inside the controller, but not for same reason that you think. You should avoid new, because it causes tight coupling to the name of class. Instead you should provide your Controller instance with a Factory in constructor.

    $factory = new DomainFactory( new PDO(...), $cache );
    $controller = new Foobar( $factory );
    
    $controller->$command($request);
    

    This you could use in the controllers method like this:

    public function __construct( $domain_factory )
    {
        $this->factory = $domain_factory
    }
    
    public function do_stuff( $request )
    {
        $id = $request->getQuery('id');
        $articles = $this->factory->build('news')->get_article($id);
        // thought i would split this line into two parts
    }
    

    Oh .. and what factory would do, would be this:

    public function __construct( $pdo, $cache )
    {
        $this->pdo = $pdo;
        $this->cache = $cache;
    }
    
    public function build( $name )
    {
        $instance = new $name;
        $instance->assign_connection( $this->pdo );
        $instance->assign_cache( $this->cache );
        return $instance;
    }
    

This should give you some ideas ..

Here are few links which you might find helpful, if you want to learn how to do good object oriented code, which follows best practices:

Community
  • 1
  • 1
tereško
  • 58,060
  • 25
  • 98
  • 150
  • thank you for this information i'm using this in my loader class constructor spl_autoload_register(array($this,'load_controller')); spl_autoload_register(array($this,'load_models')); spl_autoload_register(array($this,'load_library')); – Hmmm Jun 18 '12 at 22:37
  • thanks for you comment it's really was helpful to change somethings in my code – Hmmm Jun 18 '12 at 22:39
  • i really want to chat with you but i'm new member and i should have 20 reputations coulde you give me your email ?? – Hmmm Jun 18 '12 at 22:43
  • @user1464822 , you do not need to register separate autoloader for each type of class. In PHP 5.3 we have namespaces, and it is really easy to map each namespace to a directory. Experiment a bit and you will see how you can utilize it. – tereško Jun 18 '12 at 23:53
  • @user1464822 , as for chat .. getting 20 reputation is really easy. It's getting an 2 upvotes, or editing grammar/spelling mistakes in 10 posts. – tereško Jun 18 '12 at 23:55
  • i really love to use namespaces but i have to support php 5.1 in my scripts to make it work good for every server – Hmmm Jun 19 '12 at 00:40