I'm implementing a Log system for PHP, and I'm a bit stuck.
All the configuration is defined in an XML file, that declares every method to be logged. XML is well parsed and converted into a multidimensional array (classname => array of methods). So far, so good.
Let's take a simple example:
#A.php
class A {
public function foo($bar) {
echo ' // Hello there !';
}
public function bar($foo) {
echo " $ù$ùmezf$z !";
}
}
#B.php
class B {
public function far($boo) {
echo $boo;
}
}
Now, let's say I've this configuration file:
<interceptor>
<methods class="__CLASS_DIR__A.php">
<method name="foo">
<log-level>INFO</log-level>
<log-message>Transaction init</log-message>
</method>
</methods>
<methods class="__CLASS_DIR__B.php">
<method name="far">
<log-level>DEBUG</log-level>
<log-message>Useless</log-message>
</method>
</methods>
</interceptor>
The thing I'd like AT RUNTIME ONLY (once the XML parser has done his job) is:
#Logger.php (its definitely NOT a final version) -- generated by the XML parser
class Logger {
public function __call($name,$args) {
$log_level = args[0];
$args = array_slice($args,1);
switch($method_name) {
case 'foo':
case 'far':
//case .....
//write in log files
break;
}
//THEN, RELAY THE CALL TO THE INITIAL METHOD
}
}
#"dynamic" A.php
class A extends Logger {
public function foo($log_level, $bar) {
parent::foo($log_level, $bar);
echo ' // Hello there !';
}
public function bar($foo) {
echo " $ù$ùmezf$z !";
}
}
#"dynamic" B.php
class B extends Logger {
public function far($log_level, $boo) {
parent::far($log_level, $bar);
echo $boo;
}
}
The big challenge here is to transform A and B into their "dynamic" versions, once the XML parser has completed its job.
The ideal would be to achieve that without modifying the code of A and B at all (I mean, in the files) - or at least find a way to come back to their original versions once the program is finished.
To be clear, I wanna find the most proper way to intercept method calls in PHP.
What are your ideas about it?
PS: and of course, there should be NO CONSEQUENCE on the client code (no different if interception is enabled or not).
You could use eval() to actually define the classes, but you should be very careful. The eval() function can be very dangerous.
Something like this:
$parentName = 'Bar';
eval('class Foo extends ' . $parentName . ' { }');
http://php.net/eval
This solution once again uses eval, but I'll post it for your consideration anyway because I think it's a really nice way of dynamic inheritance.
The method here is to use an intermediary class which extends some default class that can be changed (in this instance to a different class also extending the default).
I'm uncertain as to what it is in your setup that is not allowing for this kind of working -- if you clarify this I could perhaps provide a better recommendation.
<?php
/*
* One of the following classes will be the superclass of the Child
*/
class Ancestor {
function speak() {
echo 'Ancestor <br />';
}
}
class Mum extends Ancestor {
function speak() {
parent::speak();
echo 'Mum <br />';
}
}
class Dad extends Ancestor {
function speak() {
parent::speak();
echo 'Dad <br />';
}
}
/*
* Decide on which class we wish to make the superclass of our Child
*/
$parentClass = null;
if (isset($_GET['parent'])) {
$parentClass = $_GET['parent'];
if (!class_exists($parentClass)) {
$parentClass = "Ancestor";
}
}
if (!is_null($parentClass)) {
eval("class ChildParent extends $parentClass {};");
} else {
class ChildParent extends Ancestor {};
}
if (class_exists('ChildParent')) {
class Child extends ChildParent
{
function speak() {
parent::speak();
echo 'Child <br />';
}
}
}
/*
* Show what's going on
*/
echo 'Either | Mum | Dad <br />';
$child = new Child();
$child->speak();*
Related
I have some handler ("controller") classes and they can process items in some way:
interface IHandler
{
public function execute(Item $item);
}
class FirstHandler implements IHandler
{
public function execute(Item $item) { echo $item->getTitle(); }
}
class SecondHandler implements IHandler
{
public function execute(Item $item) { echo $item->getId() . $item->getTitle(); }
}
class Item
{
public function getId() { return rand(); }
public function getTitle() { return 'title at ' . time(); }
}
But then I need to add some new functionality in child Item class:
class NewItem extends Item
{
public function getAuthor() { return 'author ' . rand(); }
}
and use it in SecondHandler
class SecondHandler implements IHandler
{
public function execute(Item $item) { printf('%d %s, author %s', $item->getId(), $item->getTitle(), $item->getAuthor()); }
}
But Item class actually has not getAuthor method. And, if I try to change signature of accept method in SecondHandler class, I will catch E_STRICT error about declaration compatibility. And, of course, it's sort of LSP violation.
How can I fix this problem? Do I need two interfaces, for example, INewHandler and IHandler, with different signatures of execute method? But it's some sort of code duplicates.
Also, I cannot use __constructor(Item $item) and __construct(NewItem $item) in handlers (and execute method without arguments), which will be seen like a better solution: they must be immutable and only single instance of every strategy allowed in application lifecycle.
As you discovered by yourself, the type hinting implementation of PHP has a lot limitations that make scenarios, like the one described by you, harder than they should be. In other typed languages like Java and Swift your implementation is absolutely licit.
After some thinking on your question I came to the solution presented by Félix but I consider it too much over engineered compared to the problem.
My answer to your question is not a solution but an advice that I give to you after years of development with PHP:
Give up with type hinting in PHP and develop like it should be... in a dynamic way.
PHP is more similar to Ruby/Python/JavaScript than Java/C++, and trying to copy 1 to 1 from static typed languages translates in forced and convolute implementations.
The solution to your implementation problem is easy, so don't over complicate it and keep it easy as it should be (KISS principle).
Declare the methods' arguments without the type and implement a check where you really need (for example throwing an exception).
interface IStrategy
{
public function execute($item);
}
class FirstStrategy implements IStrategy
{
public function execute($item) {
echo $item->getTitle();
}
}
class SecondStrategy implements IStrategy
{
public function execute($item) {
// execute(NewItem $item) is identical to this check.
if (! $item instanceof NewItem) {
throw new Exception('$item must be an instance of NewItem');
}
echo $item->getAuthor();
}
}
class Item
{
public function getId() { return rand(); }
public function getTitle() { return 'title at ' . time(); }
}
class NewItem extends Item
{
public function getAuthor() { return 'author ' . rand(); }
}
Again, don't think in Java but follow as much as possible the duck typing way.
When possible, try to don't strictly force the type of the parameters but adapt the behavior of the code based on the available interfaces (Duck Typing).
class SecondStrategy implements IStrategy
{
public function execute($item) {
$message = $item->getTitle();
// PHP 5 interface availability check.
if (is_callable([$item, 'getAuthor'])) {
$message .= ' ' . $item->getAuthor();
}
// With PHP 7 is even better.
// try {
// $message .= ' ' . $item->getAuthor();
// } catch (Error $e) {}
echo $message;
}
}
I hope to have helped you. ^_^
Both #daniele-orlando and #ihor-burlachenko made valid points.
Consider following approach for method overloading, which is kind of a compromise and should scale well:
interface IHandler
{
/**
* #param $item Item|NewItem
*/
public function execute($item);
// protected function executeItem(Item $item);
// protected function executeNewItem(NewItem $item);
}
trait IHandlerTrait
{
public function execute($item)
{
switch(true) {
case $item instanceof Item:
return $this->executeItem($item);
case $item instanceof NewItem:
return $this->executeNewItem($item);
default:
throw new \InvalidArgumentException("Unsupported parameter type " . get_class($item));
}
}
protected function executeItem(Item $item)
{
throw new \LogicException(__CLASS__ . " cannot handle execute() for type Item");
}
protected function executeNewItem(NewItem $item)
{
throw new \LogicException(__CLASS__ . " cannot handle execute() for type NewItem");
}
}
class FirstHandler implements IHandler
{
use IIHandlerTrait;
protected function executeItem(Item $item) { echo $item->getTitle(); }
}
class SecondHandler implements IHandler
{
use IIHandlerTrait;
// only if SecondHandler still need to support `Item` for backward compatibility
protected function executeItem(Item $item) { echo $item->getId() . $item-> getTitle(); }
protected function executeNewItem(NewItem $item) { printf('%d %s, author %s', $item->getId(), $item->getTitle(), $item->getAuthor()); }
}
Are you sure you want to use Strategy pattern here?
It looks, like the strategy's action here depends on the type of the element it processes. And Visitor pattern might apply here as well in this case.
As it stands, you appear to want to execute an extensible data record (Item and NewItem). Consider instead executing some pluggable behaviour (implemented via an interface).
It's hard from your writing to guess what that behavior would be, because (New)Item is just a glorified data structure in the example you provide.
If you want to work/manipulate with object in another object, you could/should use interfaces.
interface IStrategy
{
public function execute(ItemInterface $item);
}
interface ItemInterface
{
public function getTitle();
.....
}
If you want to extend public functionality of the (New)Item class you can make new interface for newItem
interface NewItemInterface extends ItemInterface
{
...
}
class SecondStrategy implements IStrategy
{
public function execute(NewItemInterface $item)
{ .... }
}
Or you can use some instance checks as others have mentioned.
If your inheritance and suggestion that SecondHandler should handle both Item and NewItem were correct in the first place, then you should be able to hide this functionality behind the common interface. From your examples, it might be called toString() which might be a part the Item interface.
Otherwise, there might be something wrong with your design initially. And you have to change your inheritance or the way you handle items. Or something else we don't know about.
Also, I don't know why you need DTO but it seems there is some misunderstanding of Doctrine. Doctrine is an ORM and it solves your persistence problem. It adds limitations on how you communicate with your storage introducing repositories, but it doesn't define your domain logic.
As per the Interface segregation please find some solution.
```
# based on interface segrigation.
interface BasicInfo
{
public function getId();
public function getTitle();
}
interface AuthorInfo
{
public function getAuthor();
}
interface IHandler
{
public function execute(Item $item);
}
class FirstHandler implements IHandler
{
public function execute(Item $item) { echo $item->getTitle(); }
}
class SecondHandler implements IHandler
{
public function execute(Item $item) { echo $item->getId() . $item->getTitle(); }
}
class Item implements BasicInfo
{
public function getId() { return rand(); }
public function getTitle() { return 'title at ' . time(); }
}
class Item2 extends Item implements AuthorInfo
{
public function getAuthor() { return 'author ' . rand(); }
}
But I think you should not kept the dependency of the Item class. you should write some duplicated code to keep the class pluggable/independent. So the Open/close principle should also there.
In my beginning PHP class, we are having our first go at Objects and classes. My assignment question is:
Create (a) a parent class (aka “superclass”) named “Human” with one variable named “legs” and one function (aka “method”) named “walk”, (b) set the default value of “legs” to 2, and (c) make the “walk” function display “Human can walk.” when it is called.
Create (a) a child class (also known as “subclass”) named “Kids” which will inherits all members of the “Human” class, (b) create a variable “hands” of the Kids class and set its default value to 2, and (c) create a function named “jump” of the Kids class which displays a message “A kid can jump.”
Create an object of the “Kids” class named ”Kuma”, and (c) use the "Kuma" object to display the numbers of legs and call the “walk” function.
The result should print:
2 legs
Humans can walk.
2 hands
A kid can jump.
Here's my code so far. I'm having difficult with the instructions in #3.
class Human {
var $legs = 2;
var $content = "<p>Humans can walk.</p>";
function Walk($Kuma) {
echo $this->legs . " legs";
echo $this->content;
}
}
class Kids extends Human {
var $hands = 2;
var $content2 = "<p>A kid can jump.</p>";
function Jump($Kuma) {
echo $this->hands;
echo $this->content2;
}
}
$obj = new Kids(Kuma);
$obj -> Walk(Kuma);
?>
class Human {
var $legs = 2;
var $content = "<p>Humans can walk.</p>";
function Walk() {
echo $this->legs . " legs";
echo $this->content;
}
}
class Kids extends Human {
var $hands = 2;
var $content2 = "<p>A kid can jump.</p>";
function Jump() {
echo $this->hands;
echo $this->content2;
}
}
$kuma = new Kids(); // creating OBJECT kuma
$kuma -> Walk(); // calling the walk function
?>
for example:
$object = new Human(); // creating OBJECT named object of CLASS Human
You have done a few weird things in your example. For example, I have no idea, from the instructions you gave, why you want the Walk and Jump methods to output information about hands and legs.
Here would be my suggestion:
class Human {
public $legs = 2;
public function walk() {
echo 'Human can walk.';
}
}
class Kids extends Human {
public $hands = 2;
public function jump() {
echo 'A kid can jump.';
}
}
$Kuma = new Kids();
echo $Kuma->legs . " legs\n";
$Kuma->walk();
echo "\n";
echo $Kuma->hands . " hands\n";
$kuma->jump();
A few things to note:
I have used good coding practice in declaring variables and method scope (in this case public). Honestly, good coding practice would also have the class properties (legs/arms) be declared as protected and available only via getters/setters.
I did not enforce any HTML formatting within the class (I actually just used end of line characters in my example which could be substituted with HTML line breaks or paragraphs or whatever you might need). I probably would have actually not even had the class itself be responsible for output when calling methods except that is explicitly asked for. (I would have simply done return of the raw text and let caller determine formatting for output).
I remove hands/legs output from walk/jump. This has nothing to do with those methods and should not be mixed.
I've been trying for a long time now to find a correct design using PHP to achieve what I want, but everything I've tried failed and I'm guessing it's probably because I'm not looking from the right angle, so I wish some of you can enlighten me and give me some good advice!
The design might seem a little weird at first, but I assure you it's not because I like to make things complicated. For the sake of simplicity I'm only giving the minimal structure of my problem and not the actual code. It starts with these:
<?php
// ------------------------------------------------------------------------
class Mother_A
{
const _override_1 = 'default';
protected static $_override_2 = array();
public static function method_a()
{
$c = get_called_class();
// Uses $c::_override_1 and $c::$_override_2
}
}
// ------------------------------------------------------------------------
class Mother_B extends Mother_A
{
public function method_b()
{
// Uses self::method_a()
}
}
Class Mother_A defines a static method that uses constants and statics to be overridden by children. This allows to define a generic method (equivalent of a "template" method) in the derived class Mother_B. Neither Mother_A or Mother_B are intended to be instanciated, but Mother_B should not be abstract. This exploits Late Static Binding, which I find very useful btw.
Now comes my problem. I want to define two classes, in n distinct 'situations' (situation 1, situation 2, etc):
<?php
// ------------------------------------------------------------------------
class Child_A_Situation_k extends Mother_A
{
// Uses method_a
}
// ------------------------------------------------------------------------
class Child_B_Situation_k extends Mother_B
{
// Uses method_a and method_b
}
Of course I'm not actually giving these stupid names; both classes have different names in each situation, but both follow the same derivation pattern from Mother_A and Mother_B. However, in each individual case ('situation'), both classes need the exact same constants/static override, and I don't know how to do that without duplicating the override manually in both classes.
I tried many things, but the closest I got was to implement an interface Interface_Situation_k that defined constants and statics for the situation k, and make both children implement this interface. Of course, you can't define statics in an interface, so it failed, but you get the idea. I would have traded the interface for a class, but then there's no multiple inheritance in PHP, so it's not valid either. :/ I'm really stuck, and I can't wait to read a possible solution! Thanks in advance!
this is the best i can do, i don't think there is a way to do it with less code.
Look at the comments inside the code for more info.
Fully working code:
<?php
class Mother_A
{
// you're using '_override_1' as a variable, so its obviously not a constant
// also i made it public for the setSituation function,
// you could keep it protected and use reflections to set it
// but i dont really see a reason for that.
// if you want that, look up how to set private/protected variables
public static $_override_1 = 'default';
public static $_override_2 = array();
public static function method_a()
{
$c = get_called_class();
var_dump($c::$_override_1);
var_dump($c::$_override_2);
// Uses $c::_override_1 and $c::$_override_2
}
public static function setSituation($className)
{
$c = get_called_class();
// iterate through the static properties of $className and $c
// and when the you find properties with the same name, set them
$rBase = new ReflectionClass($c);
$rSituation = new ReflectionClass($className);
$staBase = $rBase->getStaticProperties();
$staSituation = $rSituation->getStaticProperties();
foreach($staSituation as $name => $value)
{
if(isset($staBase[$name])) $c::$$name = $value;
}
}
}
// ------------------------------------------------------------------------
class Mother_B extends Mother_A
{
public function method_b()
{
self::method_a();
}
}
class Situation_k
{
public static $_override_1 = 'k';
public static $_override_2 = array('k','k');
}
class Child_A_Situation_k extends Mother_A { }
Child_A_Situation_k::setSituation('Situation_k');
// This is not as short as writing 'extends Mother_A, Situation_k'
// but i think you wont get it shorter
class Child_B_Situation_k extends Mother_B { }
Child_B_Situation_k::setSituation('Situation_k');
echo '<pre>';
Child_A_Situation_k::method_a();
echo "\n";
Child_B_Situation_k::method_a();
echo "\n";
Child_B_Situation_k::method_b();
echo "\n";
echo '</pre>';
?>
This is the first question I ask from many others to come.
Someone here might call me crazy because I'm following the mentioned book in the question's Title using PHP-OO.
At the first chapter, the authors introduce a simple project called 'SimUDuck' and, although I've reproduced the same in Java, I was wondering to reproduce the same using PHP.
At the end, the SimUDuck's project creates two (2) interfaces (FlyBehavior and QuackBehavior), more than five (5) classes implementing those interfaces (e.g. FlyWithWings(), Quack() etc), an abstract class called Duck and three (3) or four (4) different ducks species classes extending Duck (Mallard, HeadRedDuck, RubberDuck etc), just to demonstrate how important is to program for interface.
To simulate the Java main method environment, I've created a PHP class called MiniDuckSimulator, including the function 'public static function main()' and in the same script I've added "MiniDuckSimulator::main();". The script works without errors.
The intriguing issue is that without call any QuackBehavior::quack() implemented method, the echo 'Quack!quack!' appears. Those who has read this book knows what I'm talking about.
Note: Below is a particular part of the script:
interface FlyBehavior {
public function fly();
}
interface QuackBehavior {
public function quack();
}
include_once 'FlyBehavior.php';
class FlyWithWings implements FlyBehavior {
public function fly() {
echo 'I'm flying!<br />';
}
}
include_once 'QuackBehavior.php';
class Quack implements QuackBehavior {
public function quack() {
echo 'Quack!<br />';
}
}
abstract class Duck {
protected $flyBehavior;
protected $quackBehavior;
function __construct() {
}
public function performFly(){
$this->flyBehavior->fly();
}
public function performQuack(){
$this->quackBehavior->quack();
}
public function setFlyBehavior($flyBehavior){
$this->flyBehavior = $flyBehavior;
}
public function swim(){
echo "All the ducks float, including the decoy!<br />";
}
}
include_once 'Duck.php';
include_once 'FlyWithWings.php';
include_once 'Quack.php';
class Mallard extends Duck {
function __construct() {
$this->flyBehavior = new FlyWithWings();
$this->quackBehavior = new Quack();
}
}
class MiniDuckSimulator {
public static function main(){
$mallard = new Mallard();
$mallard->performFly();
}
}
MiniDuckSimulator::main();
Thanks in advance.
LucDaher.
The reason you are seeing Quack!<br /> output is because of this:
class Quack implements QuackBehavior {
public function quack() {
echo 'Quack!<br />';
}
}
Here's your problem: If you simply run new Quack(); the quack() method is automatically being executed by php as a constructor because it is the same name as your class. -- I see you referenced Java in your question, so this shouldn't be a foreign concept to you.
new Quack(); // => Quack!<br />
A potentially better way
<?php
interface CanFly {
public function fly();
}
interface CanQuack {
public function quack();
}
abstract class Duck implements CanFly, CanQuack {
protected $color = "DEFAULT"
public function fly(){
echo "I'm flying with my {$this->color} wings\n";
}
public function quack(){
echo "I'm quacking\n";
}
public function swim(){
echo "I'm swimming\n";
}
}
class Mallard extends Duck {
public function __construct(){
$this->color = "green";
}
public function quack(){
echo "My quack sounds more like a honk\n";
}
}
$m = new Mallard();
$m->fly();
$m->quack();
$m->swim();
?>
Output
I'm flying with my green wings
My quack sounds more like a honk
I'm swimming
In your situation, I would personally assume that I've overlooked something when saying that an echo is being reached in the code without a call to that method. I can't see a way that this would be possible.
Reanalyze your code and look for a sneaky way that your echo 'Quack!quack!' is being reached.
Comment this line:
echo 'Quack!<br />';
Do you see any more quacks? If so, then there is an echo/exit/die in your code with this string!
It is because when you have the class with the same name of the method, the PHP consider it as a constructor. This is already deprecated in php 7 and it will be discontinued soon. You can see it on the online documentation: http://php.net/manual/en/migration70.deprecated.php
I am trying to inherit a set of different parent class and even not inherit any class but as per some condition.
For example, Here is what I would like to do
$choice = 2;
switch($choice) {
case 1:
class child extends parent1
break;
case 2:
class child extends parent2
break;
default:
class child
//extend nothing
break;
}
I think you can figure out what I am trying achieve here.
parent classes
class car { }
Child classes
class ferari extends car { }
class ford extends car { }
grandchild classes
class automaticcar { }
class manualcar { }
Now this grandclasses need to interit a parent as per the value sent from the form using post. Something like this
$brand = $_POST['brand'];
if(isset($brand) && !empty($brand)) {
class automaticcar extends $brand
}
else {
class automaticcar extends car //or even nothing
}
//And then I wish to write the remaining portion of the class
The kind of inheritance you are trying to obtain is not attainable using a language which inheritance is based on classes.
The closer solution you can obtain is using a sort of decorator pattern with a bit of magic methods. something like this:
$choice = 2;
switch($choice) {
case 1:
$obj = new child(new parent1());
break;
case 2:
$obj = new child(new parent2());
break;
default:
//extend nothing
$obj = new child();
break;
}
with child being similar to this:
class child {
function __construct($composeObj) {
$this->core = $composeObj;
// wathever you need to iniyialize
}
function __call($name, $params) {
return call_user_func(array($sthis->core, $name), $parameters);
}
// other functions
} // eo child
This solution have some caveats but if you can cope with them (the object does not belongs to the family of the composited object, call_user_func does not pass the parameters by reference) this is a suitable solution.
A better solution is the factory approach suggested by sandeepan but you already refused it.
A Ferrari is not different to a Ford in the properties or methods it supplies. They are both still cars. They just have different values for their attributes. Creating a spezialized subclass shouldn't be necessary for that. Instead try this route:
class Car
{
protected $_manufacturer;
protected $_engine;
protected $_gear;
protected $_price;
protected $_color;
public function __construct($manufacturer, $engine, $gear, $price, $color)
{
// setting properties
}
}
class CarFactory
{
public static function createFerrari()
{
$engine = new Engine(500); // PS
$gear = new Gear(6, 'manual');
return new Car('Ferrari', $engine, $gear, '250000', 'red');
}
public static function createFord()
{
$engine = new Engine(90); // PS
$gear = new Gear(5, 'automatic');
return new Car('Ford', $engine, $gear, '50000', 'black');
}
// other car creation methods ...
}
If you extend a class, you are creating an is-a relationship. The subclass is a specialized parent class. Gear and Engine is nothing a Car is, but something a car has. Whenever you can describe a class to have something, it's a candidate for it's own class or for just being an attribute. Whether it should be it's own class depends on whether the thing encapsulated own unique state and responsibiliy.
First off, I really don't think you understand object oriented principles well enough to ask for this functionality. It's not really needed with the style of OOP that PHP implements.
You are requesting something like conditional mix-ins. It's possible to implement it, but it is a huge kludge and should be avoided. Here's something I put together a while ago when I was just testing some concepts:
<?php
class Mixin
{
private $objects = array();
private $funcs = array();
public function addMixin(Mixable $object)
{
$exported_vars = $object->exportVars();
foreach ($exported_vars as $key => &$ref)
$this->$key = &$ref;
$vars = array();
foreach (array_keys(get_object_vars($this)) as $key)
$vars[$key] = &$this->$key;
$object->importVars($vars);
$this->objects[] = $object;
}
public function __call($method, $args)
{
if (!isset($this->funcs[$method]))
{
$found = false;
foreach ($this->objects as $obj)
{
if (method_exists($obj, $method))
{
$found = true;
$this->funcs[$method] = array($obj, $method);
break;
}
}
if (!$found)
throw new Exception("method doesn't exist");
}
return call_user_func_array($this->funcs[$method], $args);
}
}
class Mixable
{
public function exportVars()
{
$vars = array();
foreach (array_keys(get_object_vars($this)) as $key)
{
$vars[$key] = &$this->$key;
}
return $vars;
}
public function importVars($vars)
{
foreach ($vars as $key => &$ref)
{
$this->$key = &$ref;
}
}
}
?>
You would use it like:
<?php
class Parent1 extends Mixable
{
protected $name = 'Parent 1';
public function p1()
{
print "P1\n";
}
}
class Parent2 extends Mixable
{
protected $name = 'Parent 2';
public function p2()
{
print "P2\n";
}
}
class Child1 extends Mixin
{
public function whoAmI()
{
print $this->name."\n";
}
}
$foo = new Child1();
if (mt_rand(1, 2) == 1)
{
$foo->addMixin(new Parent1());
$foo->p1();
}
else
{
$foo->addMixin(new Parent2());
$foo->p2();
}
$foo->whoAmI();
?>
Please do not try to use the code! Even if it were production ready, it's a terrible concept. I put it here to show you how it would work.
I think what you really should be doing is something more like a Factory pattern: build a CarFactory class that returns a properly subclassed Car. (Or you could create a factory method within a Car class.)
It could be something like Car::get($_POST['brand']).
Is your question "Condition based inheritance good?" Then yes it looks necessary in many cases. But I think it would be better to initiate objects conditionally instead of defining extended classes inside condition.
Updates
As far as I understand you want to have different attributes/functions of the child class depending on condition. I faced a similar need/problem in my project. There it was relating to view logic. You may check How is my approach to reuse view logic in my project?
If I understand your problem correctly, then you should have the child classes ready beforehand like this in separate php files:-
child1 class
class1 child extends parent1
child2 class
class2 child extends parent2
And in the condition part do something like:-
$choice = 2;
switch($choice) {
case 1:
include /path/to/child1;
$obj = new child1();
break;
case 2:
include /path/to/child2;
$obj = new child2();
break;
default:
include /path/to/child;
$obj = new child();
//extend nothing
break;
}
I know I'm almost SIX years late. But just in case someone lands here again, I decided to put it here.
Please note that I do not assume the implicit understanding that the class names Car, Ferrari, Ford etc are vehicles. So as to be able to apply this pattern in a generic fashion.
I'll use either of the following approaches in the decreasing order of preference:
Class alias PHP Manual (PHP 5 >= 5.3.0, PHP 7)
// Assuming $my_brand is the required brand
if (!class_exists($my_brand))
{
// Raise suitable warning here and exit
exit('Brand ' . $my_brand . 'not found.');
}
class_alias($my_brand, 'MyBrand');
class AutomaticCar extends MyBrand
{
}
Conditional stacking of inheritance (Too much work, but useful in a larger size project)
// File: lib/MyBrand/Ferrari.php
class MyBrand extends Ferrari
{
}
// File: lib/MyBrand/Ford.php
class MyBrand extends Ford
{
}
// Then in your main code, assuming $my_brand is the required brand
if (!file_exists('lib/MyBrand/' . $my_brand . '.php'))
{
// Raise suitable warning here and exit
exit('Brand ' . $my_brand . 'not found.');
}
class AutomaticCar extends MyBrand
{
}
Other patterns that I can right now (such as Factory Design and Decorator Pattern) think of would take different routes which doesn't comply with the exact topic. So thats all for now.