No matter your way is absolutely possible and of course, not so hard to make much more generic, it is as well very incorrect in the terms of Object oriented design.
Brands should be a totally different object. In your design you inject a brand new instance of Cards to the current Cars instance, only to specify properties. For this purpose you can use standard class object stdClass
.
With foreach around your Brand object (cars), you will get as keys the property names audi
, opel
, etc. And as values their models.
foreach ($cars->brand as $name => $value) {
echo $name . ' ' . $value . "<br />";
}
which will result in audi a6
, opel insignia
.
However, the thing you are looking for is the polymorphism. Each Brand is object of type Car, unless it's a brand of something else. This is the way which people might tell you it's the right one. Because when designing an application, you are seeking a good design as well as the work should be done.
Each object, Audi, Opel, etc is a child of a superclass Car. Thus, you instantiate them for a given parameter.
abstract class Car {
protected $_name;
protected $_model;
public function __construct($model) {
$this->_model = $model;
}
public function getName() {
return $this->_name;
}
public function getModel() {
return $this->_model;
}
}
class Audi extends Car { protected $_name = 'Audi'; }
class Opel extends Car { protected $_name = 'Opel'; }
class CarsFactory {
public static function createCars($name, $model) {
switch($name) {
case 'Audi':
return new Audi($model);
case 'Opel':
return new Opel($model);
}
}
}
$cars[] = CarsFactory::createCars('Audi', 'A6');
$cars[] = CarsFactory::createCars('Opel', 'Vectra');
$cars[] = CarsFactory::createCars('Opel', 'insignia');
foreach ($cars as $car) {
echo $car->getName() . ' ' . $car->getModel() . "<br/>";
}
which results into
Audi A6
Opel Vectra
Opel insignia
Another way is to inject new Model object into the cars object. This is almost what you have done, but your brand
property will not recieve the superclass, but a Model class (or Brand class)
This way, you can provide interface for iterating or for just printing, in your both objects. Model and Car.
class Car {
/*
* @var Model
*/
private $_models;
public function setModel(Model $model) {
$this->_models[] = $model;
}
public function getModels() {
return $this->_models;
}
public function getModelsByCar($car) {
foreach ($this->getModels() as $model) {
if ($model->getCarName() == $car) {
$models[] = $model;
}
}
return $models;
}
public function getCarByModel($modelName) {
foreach ($this->getModels() as $model) {
if ($model->getModelname() == $modelName) {
return $model->getCarName();
}
}
}
}
class Model {
private $_carName;
private $_modelName;
public function __construct($name, $model) {
$this->_carName = $name;
$this->_modelName = $model;
}
public function getCarName() {
return $this->_carName;
}
public function getModelName() {
return $this->_modelName;
}
}
$cars = new Car();
$cars->setModel(new Model('Audi', 'A6'));
$cars->setModel(new Model('Audi', 'V8'));
$cars->setModel(new Model('Audi', 'A8'));
$cars->setModel(new Model('Opel', 'insignia'));
$cars->setModel(new Model('Opel', 'vectra'));
foreach ($cars->getModels() as $model) {
echo $model->getCarName() . ' ' .$model->getModelName() . "<br/>";
}
echo "-----------------------------<br/>";
foreach ($cars->getModelsByCar('Audi') as $model) {
echo $model->getModelName() . "<br />";
}
echo "-----------------------------<br/>";
echo $cars->getCarByModel('insignia');
Output:
Audi A6
Audi V8
Audi A8
Opel insignia
Opel vectra
-----------------------------
A6
V8
A8
-----------------------------
Opel