6

Is something like the following possible in PHP?

$blah = 'foo1';

class foo2 extends $blah {
    //...
}

class foo1 {
    //...
}

This gives an error.

I want to dynamically set $blah so I can extend whatever class I want.

Edit: The reason for wanting to do this because I wanted to use a function out of another class in a related class. In the end it would have been something like:

Final extends foo1 extends foo2 extends foo3 extends foo4 extends parent { ... }

In the end I decided to instantiate the other class within the class and use it. Not the best options because they both you 2 of the same classes, but this won't be used that often, so it will work for now.

8 Answers 8

16

You're assuming here php executes top to bottom, but it doesn't quite work like that:

<?php
foo();  # works

function foo(){
  print "bar";
}

<?php

foo();  #dies

if( $i == 1 )
{
  function foo(){
    print "bar";
  }
}

<?php
$i = 1;
if( $i == 1 )
{
  function foo(){
    print "bar";
  }
}

foo(); #works

Now, although you can conditionally create classes:

<?php

class A { }
class B { }
if( false ){ 
  class C extends B { 
    public static function bar(){
      print "baz"; 
    }
  }
}
C::bar(); # dies

You cant instantiate one at runtime from a variable:

<?php
class A { }
class B { }
$x = 'B'; 
if( false ){ 
  class C extends $x { 
    public static function bar(){
      print "baz"; 
    }
  }
}
C::bar();
---> Parse error: syntax error, unexpected T_VARIABLE, expecting T_STRING in /tmp/eg.php on line 7

There is a way to do it with Eval, but you really don't want to go there:

<?php

class A { }
class B { }
$x = 'B'; 
if( true ){ 
 $code =<<<EOF
  class C extends $x { 
    public static function bar(){
      print "baz"; 
    }
  }
EOF;

  eval( $code );
}
C::bar();
$o = new C; 
if ( $o instanceof $x )
{
  print "WIN!\n";
}
--->barWIN!

However, there is a more important question here:

Why the hell would you want to extend a different class at runtime

Anybody using your code will want to hold you down and whip you for that.

( Alternatively, if you're into whipping, do that eval trick )

Sign up to request clarification or add additional context in comments.

6 Comments

In an ideal world people wouldn't want to do it. But it's not an ideal world. I looked this up because I'm stuck with Joomla changing the parent class for defining new "elements" between version 1.5.x and later versions. My subclass doesn't need to be different and I don't want different code bases, so I want to be able to inherit from different classes according to the version of Joomla. That's why.
It seems as though Generics not possible with PHP, disappointing, I thought of hacking it this way!
@user185631 Came here for the exact same reason.
Why the hell would you want to extend a different class at runtime? Testing, mock a static method :(
@Abdillah PHP is the wrong tool for the job there. The reason being throwing eval into the mix presents unfathomable levels of risks for security exploits. That said, you can still do this, but don't fool yourself that what you're doing is "nice" in any way, and make sure you're not tempted to employ that code in your production stack, just as a precaution.
|
4

I know this question was asked a long time ago, but the answer is relatively simple.

Assuming you want to extend class foo if class foo exists, or class bar if it doesn't, you'd use:

if(!class_exists('foo')) {
    class foo extends bar {
        function __construct() {
            parent::__construct();
        }
    }
}

class myclass extends foo{
    //YOUR CLASS HERE
}

3 Comments

That's an idea that may work...kinda ugly if there are say 5 possible classes that you may want to extend from.
Agreed, but from one of your comments it looks like you're developing for Joomla. I assume the class you're trying to extend is either available or not, depending on the version of Joomla, so I'm guessing the possible classes would be limited to two or so. Unfortunately there's no easy way (that I know of) to use a variable in lieu of a class name, i.e. you can't write class myclass extends $classvar {} so this is the best alternative. You're right though... 5+ possible classes it'll get ugly!
There is no need to add __construct to foo.
3

Using PHP overloading you can accomplish this to a certain extent.

class variable_class {
    public $orginalBaseClass;
    public $orginalArgs;

    public function __construct() {
        // Get constructor parameters.
        $this->orginalArgs = func_get_args();
        // Get class name from args or 3rd party source.
        $classname = 'stdClass';

        // Pass along args to new class.
        $this->orginalBaseClass = new $classname($this->orginalArgs);
    }

    public function __call($name, $arguments) {
        // Pass all method calls to the orginalBaseClass.
        return call_user_func_array(array($this->orginalBaseClass, $name), $arguments);
    }
}

I'm using this pattern inside a Drupal module for prefetching data from the cache.

Comments

2

I don't see how this would be particularly useful, but to answer your question... no. There's no way to dynamically do that because the generated class has to be instantiated before the variable is evaluated (if that makes sense).

To put it simply: The class must exist before the code can be properly executed.

Comments

2

If you don't have too many values for $blah, you could extend each one in a different file then require_once "classes/foo_$blah.php"

Otherwise, you're stuck with the eval() solution... good luck with that... :)

1 Comment

2

I assume that this is for ease-of-maintenance, right? Extending a class at run time really is pretty crazy.

class SuperClassOne { /* code */ }
class SuperClassTwo { /* code */ }

class IntermediateClass extends SuperClassOne { /* empty! */ }

class DescendantClassFoo extends IntermediateClass{ }
class DescendantClassBar extends IntermediateClass{ }
class DescendantClassBaz extends IntermediateClass{ }

Then, when you want to change all your DescendantClass* classes, you just have to change what the IntermediateClass extends:

class IntermediateClass extends SuperClassTwo { }

1 Comment

Bad use of single line comments. The closing brackets } are commented!
1

I tested something with defines and barking:

<?php
    define("INHERIT",A);

    class A{
        public function bark(){
            return "I'm A";
        }
    }
    class B{
        public function bark(){
            return "I'm B";
        }
    }

    class C extends INHERIT{}

    //main?
    $dog = new C();
    echo $dog->bark();
?>

the output is:

Fatal error: Class 'INHERIT' not found in D:\sites\inherit.php on line 15

so the answer for "are variable class extensions possible?" is: No.

1 Comment

you can however create a class that can inherit from anything by inheriting a MultipleInheriter class that has a list of classes in an array and then it calls methods with __call in a static context so the $this inside the methods gets translated to the current class. Only public METHODS would work, so it's a really fake inheritance. You would then call the extend() method and add a class to the list.
-2

you should have tried $$

$blah = 'foo1';
class foo2 extends $$blah {
    //...
}

class foo1 {
    //...
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.