Malibur
Malibur

Reputation: 1783

Accessing a specific instance of a class

Im pretty new to OOP PHP, and so I'm trying to learn.

I have a class called "Awesome_Car" that i define like so

class Awesome_Car {

    public $attributes;
    public $name;

    function __construct($name, $atts) {
        $this->name = $name;
        $this->attributes = $atts;
    }

} // end of class

And I instantiate this class x times somewhere in the code:

$car1 = new Awesome_Car('ford', array( 'color'=>'blue', 'seats' => 6 ));
$car2 = new Awesome_Car('bmw', array( 'color'=>'green', 'seats' => 5 ));

Now I would like to make a normal function that allows me to get - and manipulate - a specific instance of that class by name. Something like

function get_specific_car_instance($name) {

    //some code that retrives a specific instance by name

    //do stuff with instance

    //return instance
}

I have seen people storing each instance in a global variable as an array of object, but I've also read that global variables are considered bad practice? And I do find them a bit annoying to work with as well.

What would be a better way of doing this? preferably an OOP approach?

Upvotes: 0

Views: 83

Answers (2)

Erik
Erik

Reputation: 1057

You can create your own repository; a class whose only purpose is to create, track, and recover these cars. That'll allow you to avoid using a global variable. Of course, you'll need a way to access the repository then. You could always make it Static, but then you're basically back to a global in a way.

class CarRepository {

    private $cars = array();

    public function makeCar( $name, $atts ) {
       $this->cars[] = new Awesome_Car($name, $atts);
    }

    public function findByName($name) {
      foreach( $this->cars as $car ) {
        if( $car->name == $name ) {
          return $car;
        }
      }
    }
}

// you'll need a way to obtain the repository to find cars; but it means you can have different repositories in your code
$repo = new CarRepository;
$repo->makeCar( 'ford', array( 'color'=>'blue', 'seats' => 6 ) );
$repo->findByName( 'ford' );

Or a fully static version:

class CarRepository {

    private static $cars = array();

    public static function makeCar( $name, $atts ) {
       self::$cars[] = new Awesome_Car($name, $atts);
    }

    public static function findByName($name) {
      foreach( self::$cars as $car ) {
        if( $car->name == $name ) {
          return $car;
        }
      }
    }
}

// you can access this from ANYWHERE, but you can only ever have a single repository
CarRepository::makeCar( 'ford', array( 'color'=>'blue', 'seats' => 6 ) );
CarRepository::findByName( 'ford' );

Upvotes: 0

Flosculus
Flosculus

Reputation: 6946

If you are creating the instances dynamically, then storing them in an array is the generally accepted way. It doesn't have to be global however.

$cars = array();

$cars['ford'] = new Awesome_Car('ford', array( 'color'=>'blue', 'seats' => 6 ));
$cars['bmw']  = new Awesome_Car('bmw', array( 'color'=>'green', 'seats' => 5 ));

$ford = $cars['ford'];

This ofcourse can be abstracted by a function such as:

function get_car(&$cars, $name) {
    if (! isset($cars[$name])) {
        throw new \InvalidArgumentException('Car not found');
    }

    return $cars[$name];
}

$ford = get_car($cars, 'ford');

Or with more advanced container classes such as:

// Requires doctrine/common
use Doctrine\Common\Collections\ArrayCollection;

$cars = new ArrayCollection();

$cars->set('ford', new Awesome_Car('ford', array( 'color'=>'blue', 'seats' => 6 )));
$cars->set('bmw',  new Awesome_Car('bmw', array( 'color'=>'green', 'seats' => 5 )));

$ford = $cars->get('ford');

How you store them for later use depends quite a bit on how you are dynamically creating them though.

Upvotes: 3

Related Questions