Dynamic class extend - php

Is there a way to define a class so that it extends another class only if that other class is available?

There is nothing that would allow you to do
class Foo extendsIfExist Bar
But you can monkeypatch Foo with runkit's
runkit_class_adopt — Convert a base class to an inherited class, add ancestral methods when appropriate
Example from PHP Manual:
class myParent {
function parentFunc() {
echo "Parent Function Output\n";
}
}
class myChild {
}
runkit_class_adopt('myChild','myParent');
myChild::parentFunc();
The runkit extension is available from PECL. However, it's use is discouraged because needing it is almost always an indicator for a flawed design.
Disclaimer: I am only assuming something like the following example is the reason why you are asking your question. Disregard that part of the answer if it's not.
If you need certain functionality conditionally at runtime, consider aggregating the class you want to extend from, e.g. try something along the lines of
interface Loggable
{
public function log($message);
}
class Foo implements Loggable
{
protected $logger;
public function setLogger($logger)
{
$this->logger = $logger;
}
public function log($message)
{
if($this->logger !== NULL) {
return $this->logger->log($message);
}
}
}
In the example above, the functionality we want is log(). So instead of detecting if a logger class is available and then monkeypatching this functionality into our Foo class, we tell it to require this functionality by adding an interface Loggable. If a Logger class exists, we instantiate and aggregate it in Foo. If it doesnt exist, we can still call log but it wont do anything. This is much more solid.

I did it on this way.
if (class_exists('parentClass') {
class _myClass extends parentClass {}
} else {
class _myClass {}
}
class myClass extends _myClass
{
...
}

This is an answer and an extention to Pekka's answer.
Firstly at Pekka, i think the eval is totally wrong, what is wrong with
if(class_exists("bar"))
{
class foo extends bar
{
}
}
that is also my answer aswell.

Encountered a similar requirement recently, where a class in my library needed to dynamically extend from ClassB (if exists), otherwise extend from Class A.
My solution (my code is namespaced, same concept applies regardless):
namespace someNamespace;
spl_autoload_register(function($class) {
if (strcasecmp($class, 'someNamespace\SomeFakeClass') === 0) {
if (class_exists('ClassB',false)) {
class_alias('ClassB', 'someNamespace\SomeFakeClass');
} else {
class_alias('ClassA', 'someNamespace\SomeFakeClass');
}
}
}, true, true);
/** #noinspection PhpUndefinedClassInspection */
/** #noinspection PhpUndefinedNamespaceInspection */
class MyClass extends \someNamespace\SomeFakeClass {
# ... real logic here ...
}
Using the above solution, the class MyClass will dynamically inherit from ClassB if exists, otherwise it inherits from ClassA.
This solution avoids using eval, which is a big plus for me.
Hope this helps.
EDIT: Just a note, the #noinspection notation exists so that IDEs such as PHPStorm will not report errors regarding the non-existent class.

Do you mean this?
<?php
class Foo{
}
if( class_exists('Foo') ){
class SubFoo extends Foo{
}
}
if( class_exists('Bar') ){
class SubBar extends Bar{
}
}
$a = new SubFoo; // OK
$b = new SubBar; // Fatal error: Class 'SubBar' not found

Related

How can I conditionally make a class use a trait if it exists?

I want to be able to use the trait if it's available.
Obviously i cannont define that inside the class itself (syntax Error)
//fails
include_once('myTrait.php');
class foo
{
var $bar;
if (trait_exists('myTrait')) {
use myTrait;
}
}
//also fails
foo use myTrait;
//also fails
$f = new foo();
$f use myTrait;
//also fails
$f = new foo() use myTrait;
Ideal case scenario would be something like this:
class foo
{
var $bar;
}
if (file_exists('myTrait.php')) {
include_once('myTrait.php');
//make class foo use myTrait;
}
$f=new foo();
Having hard time finding documentation and traits doesn't seems very popular but in my particular case they are very useful. I also try to keep resource as low a possible by only including files if needed.
Hints, documentation and explanation welcome as usual.
The closest my search brought me was in this article http://brendan-bates.com/traits-the-right-way/
Let's say a few of these controllers (but not all of them) require a
database connection. To keep performance up, we shouldn't give every
controller the database connection. What we could do is write an
abstract class which extends BaseController which provides a database
connection. But, in the future, what if an object that is not a
controller requires a database connection? Instead of duplicating this
logic, we can use horizontal reuse.
A simple trait can be created:
trait DatabaseAware
{
protected $db;
public function setDatabase($db)
{
$this->db = $db;
}
protected function query($query)
{
$this->db->query($query);
}
}
This trait now provides classes with common database functionality.
Any class which requires a database connection, be it a controller or
a manager (or anything), can use this trait:
class IndexController extends BaseController
{
use DatabaseAware;
public function indexAction()
{
$this->query("SELECT * FROM `someTable`");
}
}
Where as I implement traits depending on the needs of my different objects. Database connection, debugging reporting, etc.
Easy!
Trait
A trait that might be available or not, will be either used or not, but will eventually help to implement an interface:
<?php
trait BarTrait
{
public function bar()
{
return 'Hey, I am your friend!';
}
}
Interface
An interface we are looking to implement:
<?php
interface BarInterface
{
/**
* #return string
*/
public function bar();
}
Class using trait
A class FooUsingBarTrait which uses a trait BarTrait to implement the aforementioned interface:
<?php
class FooUsingBarTrait implements BarInterface
{
use BarTrait;
}
Class not using trait
A class FooNotUsingBarTrait which does not use a trait BarTrait, but instead implements the aforementioned interface itself:
class FooNotUsingBarTrait implements BarInterface
{
public function bar()
{
return 'Hey, I am one of your friends!';
}
}
Conditionally create class definition
Finally, conditionally define a class Foo, depending on whether a trait BarTrait exists or not:
<?php
if (trait_exists(BarTrait::class) {
class Foo extends FooUsingBarTrait
{
}
} else {
class Foo extends FooNotUsingBarTrait
{
}
}
Create your instance
$foo = new Foo();
$foo->bar();
var_dump(
get_class($foo),
class_parents(Foo::class)
);
Note This probably makes most sense if both classes FooUsingBarTrait and FooNotUsingBarTrait implement a common interface - after all, you probably want to provide some functionality which will be shared between the two implementations: one using a trait, the other by other means (methods provided by that class).
For reference, see:
http://php.net/manual/en/function.class-parents.php
http://php.net/manual/en/function.trait-exists.php
For examples, see:
https://3v4l.org/fCLkt
https://3v4l.org/f77cn
no matter how bad it is, you can do it by extending the class.
trait AutoPilot {
function navigate() {
echo 'navigating...';
}
}
if (trait_exists('AutoPilot')) {
class Machine {
use AutoPilot;
}
} else {
class Machine {
}
}
class Car extends Machine {
}
$car = new Car;
$car->navigate();
Your question is fun, and eval() likely meets your needs. This style using code generation is ugly, but I know it works because I verified it myself on my own machine. Here's how you can do it:
$src = '
class foo {
var $bar; // and all of your other code goes here
';
if (file_exists('myTrait.php')) {
include_once('myTrait.php');
$src .= "use myTrait;\n";
}
$src .= "}";
eval ($src); // your class finally gets declared
I don't use eval() often, but it's fun when it solves a problem that otherwise cannot be conventionally solved.
Here what i've ended up with :
eval("class myClass {"
. (trait_exists('myTrait') ? "use myTrait;" : "")
. str_replace(['class ', '<?php'], '//', file_get_contents(myClass.php"))
);
Total lazyness:
Duplicate trait_exists line to add more traits
Comments out the class keyword and the <?php tag so you don't have to edit the class file
evaluates the one long line of smelly code.
This works just fine for me and 'as is' without any modification to any file except the one i paste this line in. It will probably won't be the case for you.
Consider the fact that:
don't use closing php tag
only one class by file
you need to add any other keywords (extends, implements,...)
and probably way more unexpected behaviour depending on your code
Thanks to lacalheinz for his instructive post but Steven aimed at the bulleyes with eval().

Use final on traits in PHP

What i want is the ability to make "final traits" with the behaviour as described below. I realise this is not possible with traits(or is it? that would make me so happy), but I'm just trying to convey what I want to do.
So, i want to have a trait that is
trait Content {
public final function getPostContent(){ /*...*/ }
public final function setPostContent($content){ /*...*/ }
}
What I want is
Marking the functions in the traits as final making sure that if a class uses this trait, the trait implementation is the guaranteed implementation
class MyClass {
use Content;
public function getPostContent() { // This should not be allowed
return null;
}
}
I want to be able to somehow check if a class uses a trait(i.e. $myObject instanceof Content)
class MyClass {}
class MyClassWithContent {
use Content;
}
var_dump((new MyClass) instanceof Content); // "bool(false)"
var_dump((new MyClassWithContent) instanceof Content; // "bool(true)"
Making sure that when the trait is being used, the methods name/visibility can not be changed. So, none of this should be allowed.
class MyDeceptiveClass {
use Content {
Content::getPostContent as nowItsNotCalledGetPostContentAnymore();
Content::setPostContent as protected; // And now setPostContent is protected
}
}
Methods in traits are overwritten by methods defined in a class, even if the trait method is final:
<?php
trait Bar {
final public function fizz() {
echo "buzz\n";
}
}
class Baz {
use Bar;
public function fizz() {
echo "bam\n";
}
}
$x = new Baz;
$x->fizz(); // bam
Taking a look at the precedence section in the traits documentation:
An inherited member from a base class is overridden by a member inserted by a Trait. The precedence order is that members from the current class override Trait methods, which in turn override inherited methods.

Using Interface to make a Class Trait-compatible

Is it OK (good practice OOP wise) to make a class implement a certain interface so that a trait being used in that class can access the classes functions.
I found a SO question a few days ago with an answer explaining that traits shouldn't use methods/things from the class it's being used in. What If I made a class implement an interface so it had to have those functions that the trait uses from the class? Would that be OK. I'm taking an OOP class in university next year, so I only learned what OOP I did from the internet, in case this is a bad question. :p
So here's the idea to clarify (in PHP)
trait MyTrait {
public function foo() {
return $this->bar(); // bar is in the class the trait is to be used in
}
}
class MyClass implements MyTraitCompatible {
public function bar() {
return "BAR!";
}
}
interface MyTraitCompatible {
public function bar();
}
Also, is there anyway to enforce that a class needs to implement MyTraitCompatible to use MyTrait?
Edit: (My actual goal is to have one function used in two classes that both extend another class (Eloquent) and would be completely identical but the function would not be used in all classes extending Eloquent - this is one way I thought of doing it.)
One option is that your trait could check that the class using it implements the interface you expect. Here's an example in the constructor method:
trait MyTrait {
public function __construct() {
if (!in_array('MyTraitCompatible', class_implements($this, false))) {
throw new Exception('To use this trait you must implement MyTraitCompatible!');
}
}
public function foo() {
return $this->bar(); // bar is in the class the trait is to be used in
}
}
A valid class would be:
class MyClass implements MyTraitCompatible {
use MyTrait;
public function bar() {
return "BAR!";
}
}
An invalid class would be:
class InvalidClass {
use MyTrait;
public function baz() {
return "I don't think so buddy.";
}
}
Obviously if the class using this trait has a constructor already then this would conflict. There isn't a pretty way to avoid this since the class using the trait will have precedence over the trait and would just override it. One option is that you could define a check method in the trait and call it from the methods in the trait to check compatibility, but it's not ideal:
trait MyTrait {
protected function compatible() {
if (!in_array('MyTraitCompatible', class_implements($this, false))) {
throw new Exception('To use this trait you must implement MyTraitCompatible!');
}
var_dump('Passed the test!');
}
public function foo() {
$this->compatible();
return $this->bar(); // bar is in the class the trait is to be used in
}
}
You could also replace that compatible() method with the __call() magic method - but again, you might run into conflicts if you have one defined elsewhere.

Inheritance & method params PHP

Let say I have a PHP Class:
class MyClass {
public function doSomething() {
// do somthing
}
}
and then I extend that class and override the doSomething method
class MyOtherClass extends MyClass {
public function doSomething() {
// do somthing
}
}
Q: Is it bad practice to change, add and or remove method params? e.g:
class MyOtherClass extends MyClass {
public function doSomething($newParam) {
// do somthing
// do something extra with $newParam
}
}
Thanks
In general, yes it is bad design. It breaks the design's adherence to the OOP principle of polymorphism (or at least weakens it)... which means that consumers of the parent interface will not be able to treat instances of your child class exactly as they would be able to treat instances of the parent.
Best thing to do is make a new semantically named method (semantic in this case meaning that it conveys a similar meaning to the original, with some hint as to what the param is for) which either calls the original, or else in your overridden implementation of the original method, call your new one with a sensible default.
class MyOtherClass extends MyClass {
public function doSomething() {
return $this->doSomethingWithOptions(self::$soSomethingDefaultOptions);
}
public function doSomethingWithOptions($optsParam) {
parent::doSomething();
// ...
}
}

Can I extend a class using more than 1 class in PHP?

If I have several classes with functions that I need but want to store separately for organisation, can I extend a class to have both?
i.e. class a extends b extends c
edit: I know how to extend classes one at a time, but I'm looking for a method to instantly extend a class using multiple base classes - AFAIK you can't do this in PHP but there should be ways around it without resorting to class c extends b, class b extends a
If you really want to fake multiple inheritance in PHP 5.3, you can use the magic function __call().
This is ugly though it works from class A user's point of view :
class B {
public function method_from_b($s) {
echo $s;
}
}
class C {
public function method_from_c($s) {
echo $s;
}
}
class A extends B
{
private $c;
public function __construct()
{
$this->c = new C;
}
// fake "extends C" using magic function
public function __call($method, $args)
{
$this->c->$method($args[0]);
}
}
$a = new A;
$a->method_from_b("abc");
$a->method_from_c("def");
Prints "abcdef"
You cannot have a class that extends two base classes. You could not have the following:
// this is NOT allowed (for all you google speeders)
Matron extends Nurse, HumanEntity
You could however have a hierarchy as follows...
Matron extends Nurse
Consultant extends Doctor
Nurse extends HumanEntity
Doctor extends HumanEntity
HumanEntity extends DatabaseTable
DatabaseTable extends AbstractTable
and so on.
You could use traits, which, hopefully, will be available from PHP 5.4.
Traits is a mechanism for code reuse in single inheritance languages such as PHP. A Trait is intended to reduce some limitations of single inheritance by enabling a developer to reuse sets of methods freely in several independent classes living in different class hierarchies. The semantics of the combination of Traits and classes is defined in a way, which reduces complexity and avoids the typical problems associated with multiple inheritance and Mixins.
They are recognized for their potential in supporting better composition and reuse, hence their integration in newer versions of languages such as Perl 6, Squeak, Scala, Slate and Fortress. Traits have also been ported to Java and C#.
More information: https://wiki.php.net/rfc/traits
Classes are not meant to be just collections of methods. A class is supposed to represent an abstract concept, with both state (fields) and behaviour (methods) which changes the state. Using inheritance just to get some desired behaviour sounds like bad OO design, and exactly the reason why many languages disallow multiple inheritance: in order to prevent "spaghetti inheritance", i.e. extending 3 classes because each has a method you need, and ending up with a class that inherits 100 method and 20 fields, yet only ever uses 5 of them.
There are plans for adding mix-ins soon, I believe.
But until then, go with the accepted answer. You can abstract that out a bit to make an "extendable" class:
class Extendable{
private $extender=array();
public function addExtender(Extender $obj){
$this->extenders[] = $obj;
$obj->setExtendee($this);
}
public function __call($name, $params){
foreach($this->extenders as $extender){
//do reflection to see if extender has this method with this argument count
if (method_exists($extender, $name)){
return call_user_func_array(array($extender, $name), $params);
}
}
}
}
$foo = new Extendable();
$foo->addExtender(new OtherClass());
$foo->other_class_method();
Note that in this model "OtherClass" gets to 'know' about $foo. OtherClass needs to have a public function called "setExtendee" to set up this relationship. Then, if it's methods are invoked from $foo, it can access $foo internally. It will not, however, get access to any private/protected methods/variables like a real extended class would.
Use traits as base classes. Then use them in a parent class. Extend it .
trait business{
function sell(){
}
function buy(){
}
function collectMoney(){
}
}
trait human{
function think(){
}
function speak(){
}
}
class BusinessPerson{
use business;
use human;
// If you have more traits bring more
}
class BusinessWoman extends BusinessPerson{
function getPregnant(){
}
}
$bw = new BusinessWoman();
$bw ->speak();
$bw->getPregnant();
See now business woman logically inherited business and human both;
EDIT: 2020 PHP 5.4+ and 7+
As of PHP 5.4.0 there are "Traits" - you can use more traits in one class, so the final deciding point would be whether you want really an inheritance or you just need some "feature"(trait). Trait is, vaguely said, an already implemented interface that is meant to be just used.
Currently accepted answer by #Franck will work but it is not in fact multiple inheritance but a child instance of class defined out of scope, also there is the `__call()` shorthand - consider using just `$this->childInstance->method(args)` anywhere you need ExternalClass class method in "extended" class.
Exact answer
No you can't, respectively, not really, as manual of extends keyword says:
An extended class is always dependent on a single base class, that is,
multiple inheritance is not supported.
Real answer
However as #adam suggested correctly this does NOT forbids you to use multiple hierarchal inheritance.
You CAN extend one class, with another and another with another and so on...
So pretty simple example on this would be:
class firstInheritance{}
class secondInheritance extends firstInheritance{}
class someFinalClass extends secondInheritance{}
//...and so on...
Important note
As you might have noticed, you can only do multiple(2+) intehritance by hierarchy if you have control over all classes included in the process - that means, you can't apply this solution e.g. with built-in classes or with classes you simply can't edit - if you want to do that, you are left with the #Franck solution - child instances.
...And finally example with some output:
class A{
function a_hi(){
echo "I am a of A".PHP_EOL."<br>".PHP_EOL;
}
}
class B extends A{
function b_hi(){
echo "I am b of B".PHP_EOL."<br>".PHP_EOL;
}
}
class C extends B{
function c_hi(){
echo "I am c of C".PHP_EOL."<br>".PHP_EOL;
}
}
$myTestInstance = new C();
$myTestInstance->a_hi();
$myTestInstance->b_hi();
$myTestInstance->c_hi();
Which outputs
I am a of A
I am b of B
I am c of C
<?php
// what if we want to extend more than one class?
abstract class ExtensionBridge
{
// array containing all the extended classes
private $_exts = array();
public $_this;
function __construct() {$_this = $this;}
public function addExt($object)
{
$this->_exts[]=$object;
}
public function __get($varname)
{
foreach($this->_exts as $ext)
{
if(property_exists($ext,$varname))
return $ext->$varname;
}
}
public function __call($method,$args)
{
foreach($this->_exts as $ext)
{
if(method_exists($ext,$method))
return call_user_method_array($method,$ext,$args);
}
throw new Exception("This Method {$method} doesn't exists");
}
}
class Ext1
{
private $name="";
private $id="";
public function setID($id){$this->id = $id;}
public function setName($name){$this->name = $name;}
public function getID(){return $this->id;}
public function getName(){return $this->name;}
}
class Ext2
{
private $address="";
private $country="";
public function setAddress($address){$this->address = $address;}
public function setCountry($country){$this->country = $country;}
public function getAddress(){return $this->address;}
public function getCountry(){return $this->country;}
}
class Extender extends ExtensionBridge
{
function __construct()
{
parent::addExt(new Ext1());
parent::addExt(new Ext2());
}
public function __toString()
{
return $this->getName().', from: '.$this->getCountry();
}
}
$o = new Extender();
$o->setName("Mahdi");
$o->setCountry("Al-Ahwaz");
echo $o;
?>
I have read several articles discouraging inheritance in projects (as opposed to libraries/frameworks), and encouraging to program agaisnt interfaces, no against implementations.
They also advocate OO by composition: if you need the functions in class a and b, make c having members/fields of this type:
class C
{
private $a, $b;
public function __construct($x, $y)
{
$this->a = new A(42, $x);
$this->b = new B($y);
}
protected function DoSomething()
{
$this->a->Act();
$this->b->Do();
}
}
Multiple inheritance seems to work at the interface level.
I made a test on php 5.6.1.
Here is a working code:
<?php
interface Animal
{
public function sayHello();
}
interface HairyThing
{
public function plush();
}
interface Dog extends Animal, HairyThing
{
public function bark();
}
class Puppy implements Dog
{
public function bark()
{
echo "ouaf";
}
public function sayHello()
{
echo "hello";
}
public function plush()
{
echo "plush";
}
}
echo PHP_VERSION; // 5.6.1
$o = new Puppy();
$o->bark();
$o->plush();
$o->sayHello(); // displays: 5.6.16ouafplushhello
I didn't think that was possible, but I stumbled upon in the SwiftMailer source code, in the Swift_Transport_IoBuffer class, which has the following definition:
interface Swift_Transport_IoBuffer extends Swift_InputByteStream, Swift_OutputByteStream
I didn't play with it yet, but I thought it might be interesting to share.
I just solved my "multiple inheritance" problem with:
class Session {
public $username;
}
class MyServiceResponsetype {
protected $only_avaliable_in_response;
}
class SessionResponse extends MyServiceResponsetype {
/** has shared $only_avaliable_in_response */
public $session;
public function __construct(Session $session) {
$this->session = $session;
}
}
This way I have the power to manipulate session inside a SessionResponse which extends MyServiceResponsetype still being able to handle Session by itself.
If you want to check if a function is public see this topic : https://stackoverflow.com/a/4160928/2226755
And use call_user_func_array(...) method for many or not arguments.
Like this :
class B {
public function method_from_b($s) {
echo $s;
}
}
class C {
public function method_from_c($l, $l1, $l2) {
echo $l.$l1.$l2;
}
}
class A extends B {
private $c;
public function __construct() {
$this->c = new C;
}
public function __call($method, $args) {
if (method_exists($this->c, $method)) {
$reflection = new ReflectionMethod($this->c, $method);
if (!$reflection->isPublic()) {
throw new RuntimeException("Call to not public method ".get_class($this)."::$method()");
}
return call_user_func_array(array($this->c, $method), $args);
} else {
throw new RuntimeException("Call to undefined method ".get_class($this)."::$method()");
}
}
}
$a = new A;
$a->method_from_b("abc");
$a->method_from_c("d", "e", "f");
You are able to do that using Traits in PHP which announced as of PHP 5.4
Here is a quick tutorial for you, http://culttt.com/2014/06/25/php-traits/
One of the problems of PHP as a programming language is the fact that you can only have single inheritance. This means a class can only inherit from one other class.
However, a lot of the time it would be beneficial to inherit from multiple classes. For example, it might be desirable to inherit methods from a couple of different classes in order to prevent code duplication.
This problem can lead to class that has a long family history of inheritance which often does not make sense.
In PHP 5.4 a new feature of the language was added known as Traits. A Trait is kind of like a Mixin in that it allows you to mix Trait classes into an existing class. This means you can reduce code duplication and get the benefits whilst avoiding the problems of multiple inheritance.
Traits
PHP does not yet support multiple class inheritance, it does however support multiple interface inheritance.
See http://www.hudzilla.org/php/6_17_0.php for some examples.
PHP does not allow multiple inheritance, but you can do with implementing multiple interfaces. If the implementation is "heavy", provide skeletal implementation for each interface in a seperate class. Then, you can delegate all interface class to these skeletal implementations via object containment.
Always good idea is to make parent class, with functions ... i.e. add this all functionality to parent.
And "move" all classes that use this hierarchically down. I need - rewrite functions, which are specific.
class A extends B {}
class B extends C {}
Then A has extended both B and C

Categories