Is it possible to extend a class dynamically? - php

I have a class which I need to use to extend different classes (up to hundreds) depending on criteria. Is there a way in PHP to extend a class by a dynamic class name?
I assume it would require a method to specify extension with instantiation.
Ideas?

While it's still not possible and not exactly your answer i needed the same thing and didn't wanted to use eval, monkey-patching etc. So i used a default class by extending it in conditions.
Of course it means if you have 100 classes to extend you need to add 100 conditions with another extending operation but for me this looked like the right way.
<?php
if(class_exists('SolutionClass')) {
class DynamicParent extends SolutionClass {}
} else {
class DynamicParent extends DefaultSolutionClass {}
}
class ProblemChild extends DynamicParent {}
?>

Yes. I like the answer with eval, but a lot of people afraid of any eval in their code, so here's one with no eval:
<?php //MyClass.php
namespace my\namespace;
function get_dynamic_parent() {
return 'any\other\namespace\ExtendedClass';// return what you need
}
class_alias(get_dynamic_parent(), 'my\namespace\DynamicParent');
class MyClass extends DynamicParent {}

It is possible to create dynamic inheritance in PHP using the power of the magic __call function. It takes a little bit of infrastructure code to work but isn't too daunting.
Disclaimer
You really ought to think at least twice before using this technique as it's actually kind of bad thing to do.
The only reason I'm using this technique is because I don't want to have to either create the interface definitions or setup the dependency injections when creating templates for a site. I want to just be able to just define a couple of function 'blocks' in a template and then have inheritance automatically use the correct 'block'.
Implementation
The steps required are:
The child class now extends a 'DynamicExtender' class. This class intercepts any calls made by the child class, to methods that don't exist in the child class and redirects them to the parent instance.
Each 'ParentClass' is extended to a 'ProxyParentClass'. For every accessible method in the parent class, there exists an equivalent method in the 'ProxyParentClass'. Each of those methods in the 'ProxyParentClass' checks to see if the method exists in the ChildClass and calls the childs version of the function if it exists, otherwise it calls the version from ParentClass
When the DynamicExtender class is constructed you pass in what parent class you require, the DynamicExtender creates a new instance of that class, and sets itself as the child of the ParentClass.
So, now when we create the child object we can specify the parent class required and the DynamicExtender will create it for us, and it will appear as if the child class is extended from the class we requested at run-time rather than it being hard-coded.
This may be easier to understand as a couple of images:
Fixed inheritance is fixed
Dynamic inheritance with proxies
Demo implementation
The code for this solution is available on Github and a slightly fuller explanation of how this can be used here, but the code for the above image is:
//An interface that defines the method that must be implemented by any renderer.
interface Render {
public function render();
}
/**
* Class DynamicExtender
*/
class DynamicExtender implements Render {
var $parentInstance = null;
/**
* Construct a class with it's parent class chosen dynamically.
*
* #param $parentClassName The parent class to extend.
*/
public function __construct($parentClassName) {
$parentClassName = "Proxied".$parentClassName;
//Check that the requested parent class implements the interface 'Render'
//to prevent surprises later.
if (is_subclass_of($parentClassName, 'Render') == false) {
throw new Exception("Requested parent class $parentClassName does not implement Render, so cannot extend it.");
}
$this->parentInstance = new $parentClassName($this);
}
/**
* Magic __call method is triggered whenever the child class tries to call a method that doesn't
* exist in the child class. This is the case whenever the child class tries to call a method of
* the parent class. We then redirect the method call to the parentInstance.
*
* #param $name
* #param array $arguments
* #return mixed
* #throws PHPTemplateException
*/
public function __call($name, array $arguments) {
if ($this->parentInstance == null) {
throw new Exception("parentInstance is null in Proxied class in renderInternal.");
}
return call_user_func_array([$this->parentInstance, $name], $arguments);
}
/**
* Render method needs to be defined to satisfy the 'implements Render' but it
* also just delegates the function to the parentInstance.
* #throws Exception
*/
function render() {
$this->parentInstance->render();
}
}
/**
* Class PageLayout
*
* Implements render with a full HTML layout.
*/
class PageLayout implements Render {
//renders the whole page.
public function render() {
$this->renderHeader();
$this->renderMainContent();
$this->renderFooter();
}
//Start HTML page
function renderHeader() {
echo "<html><head></head><body>";
echo "<h2>Welcome to a test server!</h2>";
echo "<span id='mainContent'>";
}
//Renders the main page content. This method should be overridden for each page
function renderMainContent(){
echo "Main content goes here.";
}
//End the HTML page, including Javascript
function renderFooter(){
echo "</span>";
echo "<div style='margin-top: 20px'>Dynamic Extension Danack#basereality.com</div>";
echo "</body>";
echo "<script type='text/javascript' src='jquery-1.9.1.js' ></script>";
echo "<script type='text/javascript' src='content.js' ></script>";
echo "</html>";
}
//Just to prove we're extending dynamically.
function getLayoutType() {
return get_class($this);
}
}
/**
* Class ProxiedPageLayout
*
* Implements render for rendering some content surrounded by the opening and closing HTML
* tags, along with the Javascript required for a page.
*/
class ProxiedPageLayout extends PageLayout {
/**
* The child instance which has extended this class.
*/
var $childInstance = null;
/**
* Construct a ProxiedPageLayout. The child class must be passed in so that any methods
* implemented by the child class can override the same method in this class.
* #param $childInstance
*/
function __construct($childInstance){
$this->childInstance = $childInstance;
}
/**
* Check if method exists in child class or just call the version in PageLayout
*/
function renderHeader() {
if (method_exists ($this->childInstance, 'renderHeader') == true) {
return $this->childInstance->renderHeader();
}
parent::renderHeader();
}
/**
* Check if method exists in child class or just call the version in PageLayout
*/
function renderMainContent(){
if (method_exists ($this->childInstance, 'renderMainContent') == true) {
return $this->childInstance->renderMainContent();
}
parent::renderMainContent();
}
/**
* Check if method exists in child class or just call the version in PageLayout
*/
function renderFooter(){
if (method_exists ($this->childInstance, 'renderFooter') == true) {
return $this->childInstance->renderFooter();
}
parent::renderFooter();
}
}
/**
* Class AjaxLayout
*
* Implements render for just rendering a panel to replace the existing content.
*/
class AjaxLayout implements Render {
//Render the Ajax request.
public function render() {
$this->renderMainContent();
}
//Renders the main page content. This method should be overridden for each page
function renderMainContent(){
echo "Main content goes here.";
}
//Just to prove we're extending dynamically.
function getLayoutType() {
return get_class($this);
}
}
/**
* Class ProxiedAjaxLayout
*
* Proxied version of AjaxLayout. All public functions must be overridden with a version that tests
* whether the method exists in the child class.
*/
class ProxiedAjaxLayout extends AjaxLayout {
/**
* The child instance which has extended this class.
*/
var $childInstance = null;
/**
* Construct a ProxiedAjaxLayout. The child class must be passed in so that any methods
* implemented by the child class can override the same method in this class.
* #param $childInstance
*/
function __construct($childInstance){
$this->childInstance = $childInstance;
}
/**
* Check if method exists in child class or just call the version in AjaxLayout
*/
function renderMainContent() {
if (method_exists ($this->childInstance, 'renderMainContent') == true) {
return $this->childInstance->renderMainContent();
}
parent::renderMainContent();
}
}
/**
* Class ImageDisplay
*
* Renders some images on a page or Ajax request.
*/
class ImageDisplay extends DynamicExtender {
private $images = array(
"6E6F0115.jpg",
"6E6F0294.jpg",
"6E6F0327.jpg",
"6E6F0416.jpg",
"6E6F0926.jpg",
"6E6F1061.jpg",
"6E6F1151.jpg",
"IMG_4353_4_5_6_7_8.jpg",
"IMG_4509.jpg",
"IMG_4785.jpg",
"IMG_4888.jpg",
"MK3L5774.jpg",
"MK3L5858.jpg",
"MK3L5899.jpg",
"MK3L5913.jpg",
"MK3L7764.jpg",
"MK3L8562.jpg",
);
//Renders the images on a page, along with a refresh button
function renderMainContent() {
$totalImages = count($this->images);
$imagesToShow = 4;
$startImage = rand(0, $totalImages - $imagesToShow);
//Code inspection will not be available for 'getLayoutType' as it
//doesn't exist statically in the class hierarchy
echo "Parent class is of type: ".$this->getLayoutType()."<br/>";
for($x=0 ; $x<$imagesToShow ; $x++) {
echo "<img src='images/".$this->images[$startImage + $x]."'/>";
}
echo "<br/> <br/>";
echo "<span onclick='loadImagesDynamic();' style='border: 2px solid #000000; padding: 4px:'>Click to refresh images</span>";
}
}
$parentClassName = 'PageLayout';
if (isset($_REQUEST['panel']) && $_REQUEST['panel']) {
//YAY! Dynamically set the parent class.
$parentClassName = 'AjaxLayout';
}
$page = new ImageDisplay($parentClassName);
$page->render();

I don't think it's possible to dynamically extend a class (however if I'm wrong I'd love to see how it's done). Have you thought about using the Composite pattern (http://en.wikipedia.org/wiki/Composite_pattern, http://devzone.zend.com/article/7)? You could dynamically composite another class (even multiple classes - this is often used as a work around to multiple inheritance) to 'inject' the methods/properties of your parent class into the child class.

Couldn't you just use an eval?
<?php
function dynamic_class_name() {
if(time() % 60)
return "Class_A";
if(time() % 60 == 0)
return "Class_B";
}
eval(
"class MyRealClass extends " . dynamic_class_name() . " {" .
# some code string here, possibly read from a file
. "}"
);
?>

I have solved my same type of problem. The first parameter defines the original class name and the second parameter defines the new class name of class_alias function. Then we can use this function in if and else condition.
if(1==1){
class_alias('A', 'C');
}
else{
class_alias('B', 'C');
}
class Apple extends C{
...
}
Apple class extends to virtual class "C" which can be defined as class "A" Or "B" depend on if and else condition.
For More information you can check this link https://www.php.net/manual/en/function.class-alias.php

Get All declared_classes
Position, where the class will be declare.
class myClass {
public $parentVar;
function __construct() {
$all_classes = get_declared_classes(); // all classes
$parent = $parent[count($parent) -2]; //-2 is the position
$this->parentVar = new $parent();
}
}

I have an idea so simple, you can try
class A {}
class B {}
$dynamicClassName = "A";
eval("class DynamicParent extends $dynamicClassName {}");
class C extends DynamicParent{
// extends success
// Testing
function __construct(){
echo get_parent_class('DynamicParent'); exit; //A :)
}
}

I had to do this with a processor class that extends one of two abstract classes.
The working solution looks like this:
if (class_exists('MODX\Revolution\Processors\Processor')) {
abstract class DynamicProcessorParent extends
MODX\Revolution\Processors\Processor {}
} else {
abstract class DynamicProcessorParent extends modProcessor {}
}
class NfSendEmailProcessor extends DynamicProcessorParent {
/* Concrete class */
}
If the abstract parent classes contain abstract methods, they don't need to be implemented in either of the dynamic parent classes.
If you're working on a large project, you probably don't want to use DynamicParent as the class name unless the classes are namespaced . You'll need something more specific to avoid collisions .

Related

Override Extended Class's Method Visability

Is there a way to override an extended classes method visibility without overriding the whole method?
class A
{
public function perform()
{
// Do a bunch of stuff that you don't want to override.
}
}
class B extends A
{
/*
* Change perform()'s viability from public
* to protected without re-coding the whole method.
*/
}
// You can not do this.
$b = new B();
$b->perform();
You can create a protected method that simply calls the parent method:
class B extends A
{
protected function perform() {
parent::perform();
}
}

Invocation parameter types are not compatible with declared

Phpstorm has inspection: Invocation parameter types are not compatible with declared.
I was suprised that php allow use base type as subtype.
interface Base
{
public function getId();
}
interface Child extends Base
{
}
interface SecondChildType extends Base
{
}
class ChildImpl implements Child
{
public function getId()
{
return 1;
}
}
class SecondChildTypeImpl implements SecondChildType
{
public function getId()
{
return 2;
}
}
class BaseService
{
public function process(Base $base)
{
$childService = new ChildService($base);
return $childService->process($base); //Invocation parameter types are not compatible with declared
}
}
class ChildService
{
public function process(Child $child)
{
return $child->getId();
}
}
class InheritanceTest extends \PHPUnit_Framework_TestCase
{
public function testInterfacesCanUsesAsSubstitute()
{
$baseService = new BaseService();
$this->assertEquals(1, $baseService->process(new ChildImpl()));
}
/**
* #expectedException \TypeError
*/
public function testInterfacesCanUsesAsSubstitute_Exception()
{
$baseService = new BaseService();
$baseService->process(new SecondChildTypeImpl());
}
}
Why first test pass? Why php allowed it?
PhpStorm is warning you that your code potentially allows for an instance of Base to BaseService::process that is NOT a valid Child instance, and therefore can't be passed to ChildService::process.
In your first unit test you provided an instance of Child, which extends Base, so it worked.
In your second unit test you prove in fact that it's possible to cause a PHP error. PhpStorm is simply warning you in advance that your typehints allow for this problem.
If BaseService::process will always call ChildService::process like you have right now, then BaseService::process should typehint its argument to be compatible with ChildService::process as well.
I've modified your code a bit, rewritten some of the class names to be simpler, and removed the getId method. I just want to show this as simple as possible, to help you understand what's going on.
interface Base {}
interface Child extends Base {}
interface Base2 extends Base {}
// This class implements Child, which extends Base. So this will meet either requirement.
class Class1 implements Child {}
// This class implements Base2, which extends Base.
// So this will meet any Base requirement, but NOT a Child requirement
class Class2 implements Base2 {}
class BaseService
{
/**
* Problem! We are requiring Base here, but then we pass the same argument to
* ChildService->process, which requires Child.
*
* 1) Class1 WILL work, since it implements Child which extends Base.
*
* 2) Class2 WILL NOT work. Or at least, we can't pass it to ChildService->process
* since it only implements Base2 which extends Base. It doesn't implement Child,
* therefore ChildService->process won't accept it.
*/
public function process(Base $base)
{
$childService = new ChildService($base);
return $childService->process($base);
}
}
class ChildService
{
/**
* I will ONLY receive an instance that implements Child.
* Class1 will work, but not Class2.
*/
public function process(Child $child)
{
return $child->getId();
}
}
$service = new BaseService();
// I can do this! I'm passing in Child1, which implements Child, which extends Base.
// So it fulfills the initial Base requirement, and the secondary Child requirement.
$service->process(new Child1());
// I can't do this. While BaseService will initially accept it, ChildService will refuse
// it because this doesn't implement the Child interface as required.
$service->process(new Child2());
I think you're expecting a Liskov Substitution Principle violation, but that's not the case here: ChildService does not derive from BaseService.
As you know, derived classes satisfy base class type hints, but derived class methods cannot strengthen the API of base class methods. So you can pass a Child into a method accepting a Base, but you can't strengthen the signature of a method shared between Child and Base.
The following classic code demonstrates the attempt to violate LSP, and throws a fatal "Declaration must be compatible":
abstract class AbstractService { }
abstract class AbstractFactory { abstract function make(AbstractService $s); }
class ConcreteService extends AbstractService { }
class ConcreteFactory extends AbstractFactory { function make(ConcreteService $s) {} }
You do something very similar in your code, with the crucial difference that ChildService does not inherit from an abstract BaseService. Thus ChildService is free to accept whatever arguments it wants, and there is no fatal error from PHP. If you change base service to abstract and derive child service from it, you'll get an LSP violation. (See also this question.)
Now, BaseService::process() accepts a ChildImpl because ChildImpl is-a Base. It also accepts anything implementing Child, and anything implementing Base. That means the following code is valid:
class BaseImpl implements Base {
public function getId() { return 0; }
}
(new BaseService)->process(new BaseImpl);
But this will blow up, because BaseService::process hands off to ChildService::process, which takes a Child -- and BaseImpl is not a Child. PHPStorm has performed this static analysis, and it is warning you of the possible run-time consequence of the design.

Injecting DB class into the __constructor variable inside an Abstract Class

Unable to inject Laravel's DB class into an abstract class located in another namespace folder.
Getting Error "Call to undefined method Illuminate\Support\Facades\DB::table()"
-Check:Working-
FrontController.php
<?php
use MyProject\MainPages\Front;
class indexController extends \BaseController {
/**
* #var Front
*/
private $Front;
/**
* #param ProductRepository $productRepo
*/
function __construct(Front $Front)
{
//Test
//$this->Front = $Front->goSetup();
}
}
-Check:Working-
Front.php
<?php namespace MyProject\MainPages;
use MyProject\MainPages\NavigationSkeleton;
class Front extends NavigationBluPrint {
/**
* Begins the process, Step 1
*/
protected function goSetup() {
// $this->DB->table() etc
}
}
-Not Working-
NavigationBluPrint.php
<?php namespace MyProject\MainPages;
use \DB;
abstract class NavigationBluPrint {
/**
* #var DB Laravel Database connection
*/
protected $dB;
public function __construct(DB $dB)
{
// SetDB so when extended it's already set for extended classes
$this->dB = $dB;
// Test below
$x = $this->dB->table('products')->get(); //Error: Call to undefined method Illuminate\Support\Facades\DB::table()
echo '<pre>';
print_r($x);
echo '<pre>';
}
}
If I need to do something with App:: to make this work, I dont understand how it's done. Thank you
Solution Found:In case someone else runs into the same problem.
In abstract class "NavigationBluPrint.php"
I replaced \DB; with=> use \Illuminate\Database\DatabaseManager as DB;
It seems to fix the problem, although I'm not sure whether its instantiating a new DB from start or using the same one. If former then it kind of defeats the purpose.
You're type hinting the facade for the DB class, not the DB class itself.
It's false the idea of using static method, via object and it is impossible.
you should create repository for your database operation then you can inject them greatly.
directions to create Eloquent repository or DB repository :
Here I found out a great article to do this.

Why calling parent’s method in child object works in PHP?

I found something strange in the process of PHP object inheritance.
I can call NON static parent method from a subclass.
I cannot find any information about the possibility of this happening. Moreover, the PHP interpreter does not display errors.
Why it is possible?
Is this normal PHP feature?
Is it bad practice?
Here you are a code that you can use to test it.
<?php
class SomeParent {
// we will initialize this variable right here
private $greeting = 'Hello';
// we will initialize this in the constructor
private $bye ;
public function __construct()
{
$this->bye = 'Goodbye';
}
public function sayHi()
{
print $this->greeting;
}
public function sayBye()
{
print $this->bye;
}
public static function saySomething()
{
print 'How are you?';
}
}
class SomeChild extends SomeParent {
public function __construct()
{
parent::__construct();
}
/**
* Let's see what happens when we call a parent method
* from an overloaded method of its child
*/
public function sayHi()
{
parent::sayHi();
}
/**
* Let's call a parent method from an overloaded method of
* its child. But this time we will try to see if it will
* work for parent properties that were initialized in the
* parent's constructor
*/
public function sayBye()
{
parent::sayBye();
}
/**
* Let's see if calling static methods on the parent works
* from an overloaded static method of its child.
*/
public static function saySomething()
{
parent::saySomething();
}
}
$obj = new SomeChild();
$obj->sayHi(); // prints Hello
$obj->sayBye(); // prints Goodbye
SomeChild::saySomething(); // prints How are you?
That's the way, methods of a parent class are called from subclasses in PHP. If you override a method, you often need a way to include the functionality of the parent's method. PHP provides this via the parent keyword. See http://www.php.net/manual/en/keyword.parent.php.
This is a default functionality of PHP, In this way even after overriding the parent method, you can still add its existing functionality in child method.
ex-
class vehicle {
function horn()
{
echo "poo poo";
}
}
class audi extends vehicle {
function horn()
{
parent::horn();
echo "pee pee";
}
}
$newvehicle =new audi();
$newvehicle->horn(); // this will print out "poo poo pee pee"

Nested or Inner Class in PHP

I'm building a User Class for my new website, however this time I was thinking to build it little bit differently...
C++, Java and even Ruby (and probably other programming languages) are allowing the use of nested/inner classes inside the main class, which allows us to make the code more object-oriented and organized.
In PHP, I would like to do something like so:
<?php
public class User {
public $userid;
public $username;
private $password;
public class UserProfile {
// some code here
}
private class UserHistory {
// some code here
}
}
?>
Is that possible in PHP? How can I achieve it?
UPDATE
If it's impossible, will future PHP versions might support nested classes?
Intro:
Nested classes relate to other classes a little differently than outer classes. Taking Java as an example:
Non-static nested classes have access to other members of the enclosing class, even if they are declared private. Also, non-static nested classes require an instance of the parent class to be instantiated.
OuterClass outerObj = new OuterClass(arguments);
outerObj.InnerClass innerObj = outerObj.new InnerClass(arguments);
There are several compelling reasons for using them:
It is a way of logically grouping classes that are only used in one place.
If a class is useful to only one other class, then it is logical to
relate and embed it in that class and keep the two together.
It increases encapsulation.
Consider two top-level classes, A and B, where B needs access to
members of A that would otherwise be declared private. By hiding class
B within class A, A's members can be declared private and B can access
them. In addition, B itself can be hidden from the outside world.
Nested classes can lead to more readable and maintainable code.
A nested class usually relates to it's parent class and together form a "package"
In PHP
You can have similar behavior in PHP without nested classes.
If all you want to achieve is structure/organization, as Package.OuterClass.InnerClass, PHP namespaces might sufice. You can even declare more than one namespace in the same file (although, due to standard autoloading features, that might not be advisable).
namespace;
class OuterClass {}
namespace OuterClass;
class InnerClass {}
If you desire to emulate other characteristics, such as member visibility, it takes a little more effort.
Defining the "package" class
namespace {
class Package {
/* protect constructor so that objects can't be instantiated from outside
* Since all classes inherit from Package class, they can instantiate eachother
* simulating protected InnerClasses
*/
protected function __construct() {}
/* This magic method is called everytime an inaccessible method is called
* (either by visibility contrains or it doesn't exist)
* Here we are simulating shared protected methods across "package" classes
* This method is inherited by all child classes of Package
*/
public function __call($method, $args) {
//class name
$class = get_class($this);
/* we check if a method exists, if not we throw an exception
* similar to the default error
*/
if (method_exists($this, $method)) {
/* The method exists so now we want to know if the
* caller is a child of our Package class. If not we throw an exception
* Note: This is a kind of a dirty way of finding out who's
* calling the method by using debug_backtrace and reflection
*/
$trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS, 3);
if (isset($trace[2])) {
$ref = new ReflectionClass($trace[2]['class']);
if ($ref->isSubclassOf(__CLASS__)) {
return $this->$method($args);
}
}
throw new \Exception("Call to private method $class::$method()");
} else {
throw new \Exception("Call to undefined method $class::$method()");
}
}
}
}
Use case
namespace Package {
class MyParent extends \Package {
public $publicChild;
protected $protectedChild;
public function __construct() {
//instantiate public child inside parent
$this->publicChild = new \Package\MyParent\PublicChild();
//instantiate protected child inside parent
$this->protectedChild = new \Package\MyParent\ProtectedChild();
}
public function test() {
echo "Call from parent -> ";
$this->publicChild->protectedMethod();
$this->protectedChild->protectedMethod();
echo "<br>Siblings<br>";
$this->publicChild->callSibling($this->protectedChild);
}
}
}
namespace Package\MyParent
{
class PublicChild extends \Package {
//Makes the constructor public, hence callable from outside
public function __construct() {}
protected function protectedMethod() {
echo "I'm ".get_class($this)." protected method<br>";
}
protected function callSibling($sibling) {
echo "Call from " . get_class($this) . " -> ";
$sibling->protectedMethod();
}
}
class ProtectedChild extends \Package {
protected function protectedMethod() {
echo "I'm ".get_class($this)." protected method<br>";
}
protected function callSibling($sibling) {
echo "Call from " . get_class($this) . " -> ";
$sibling->protectedMethod();
}
}
}
Testing
$parent = new Package\MyParent();
$parent->test();
$pubChild = new Package\MyParent\PublicChild();//create new public child (possible)
$protChild = new Package\MyParent\ProtectedChild(); //create new protected child (ERROR)
Output:
Call from parent -> I'm Package protected method
I'm Package protected method
Siblings
Call from Package -> I'm Package protected method
Fatal error: Call to protected Package::__construct() from invalid context
NOTE:
I really don't think trying to emulate innerClasses in PHP is such a good idea. I think the code is less clean and readable. Also, there are probably other ways to achieve similar results using a well established pattern such as the Observer, Decorator ou COmposition Pattern. Sometimes, even simple inheritance is sufficient.
Real nested classes with public/protected/private accessibility were proposed in 2013 for PHP 5.6 as an RFC but did not make it (No voting yet, no update since 2013 - as of 2021/02/03):
https://wiki.php.net/rfc/nested_classes
class foo {
public class bar {
}
}
At least, anonymous classes made it into PHP 7
https://wiki.php.net/rfc/anonymous_classes
From this RFC page:
Future Scope
The changes made by this patch mean named nested classes are easier to implement (by a tiny bit).
So, we might get nested classes in some future version, but it's not decided yet.
You cannot do this in PHP. However, there are functional ways to accomplish this.
For more details please check this post:
How to do a PHP nested class or nested methods?
This way of implementation is called fluent interface: http://en.wikipedia.org/wiki/Fluent_interface
As per Xenon's comment to Anıl Özselgin's answer, anonymous classes have been implemented in PHP 7.0, which is as close to nested classes as you'll get right now. Here are the relevant RFCs:
Nested Classes (status: withdrawn)
Anonymous Classes (status: implemented in PHP 7.0)
An example to the original post, this is what your code would look like:
<?php
public class User {
public $userid;
public $username;
private $password;
public $profile;
public $history;
public function __construct() {
$this->profile = new class {
// Some code here for user profile
}
$this->history = new class {
// Some code here for user history
}
}
}
?>
This, though, comes with a very nasty caveat. If you use an IDE such as PHPStorm or NetBeans, and then add a method like this to the User class:
public function foo() {
$this->profile->...
}
...bye bye auto-completion. This is the case even if you code to interfaces (the I in SOLID), using a pattern like this:
<?php
public class User {
public $profile;
public function __construct() {
$this->profile = new class implements UserProfileInterface {
// Some code here for user profile
}
}
}
?>
Unless your only calls to $this->profile are from the __construct() method (or whatever method $this->profile is defined in) then you won't get any sort of type hinting. Your property is essentially "hidden" to your IDE, making life very hard if you rely on your IDE for auto-completion, code smell sniffing, and refactoring.
Since PHP version 5.4 you can force create objects with private constructor through reflection. It can be used to simulate Java nested classes. Example code:
class OuterClass {
private $name;
public function __construct($name) {
$this->name = $name;
}
public function getName() {
return $this->name;
}
public function forkInnerObject($name) {
$class = new ReflectionClass('InnerClass');
$constructor = $class->getConstructor();
$constructor->setAccessible(true);
$innerObject = $class->newInstanceWithoutConstructor(); // This method appeared in PHP 5.4
$constructor->invoke($innerObject, $this, $name);
return $innerObject;
}
}
class InnerClass {
private $parentObject;
private $name;
private function __construct(OuterClass $parentObject, $name) {
$this->parentObject = $parentObject;
$this->name = $name;
}
public function getName() {
return $this->name;
}
public function getParent() {
return $this->parentObject;
}
}
$outerObject = new OuterClass('This is an outer object');
//$innerObject = new InnerClass($outerObject, 'You cannot do it');
$innerObject = $outerObject->forkInnerObject('This is an inner object');
echo $innerObject->getName() . "\n";
echo $innerObject->getParent()->getName() . "\n";
You can't do it in PHP. PHP supports "include", but you can't even do that inside of a class definition. Not a lot of great options here.
This doesn't answer your question directly, but you may be interested in "Namespaces", a terribly ugly\syntax\hacked\on\top\of PHP OOP:
http://www.php.net/manual/en/language.namespaces.rationale.php
I think I wrote an elegant solution to this problem by using namespaces. In my case, the inner class does not need to know his parent class (like the static inner class in Java). As an example I made a class called 'User' and a subclass called 'Type', used as a reference for the user types (ADMIN, OTHERS) in my example. Regards.
User.php (User class file)
<?php
namespace
{
class User
{
private $type;
public function getType(){ return $this->type;}
public function setType($type){ $this->type = $type;}
}
}
namespace User
{
class Type
{
const ADMIN = 0;
const OTHERS = 1;
}
}
?>
Using.php (An example of how to call the 'subclass')
<?php
require_once("User.php");
//calling a subclass reference:
echo "Value of user type Admin: ".User\Type::ADMIN;
?>
You can, like this, in PHP 7:
class User{
public $id;
public $name;
public $password;
public $Profile;
public $History; /* (optional declaration, if it isn't public) */
public function __construct($id,$name,$password){
$this->id=$id;
$this->name=$name;
$this->name=$name;
$this->Profile=(object)[
'get'=>function(){
return 'Name: '.$this->name.''.(($this->History->get)());
}
];
$this->History=(object)[
'get'=>function(){
return ' History: '.(($this->History->track)());
}
,'track'=>function(){
return (lcg_value()>0.5?'good':'bad');
}
];
}
}
echo ((new User(0,'Lior','nyh'))->Profile->get)();
It is waiting for voting as RFC
https://wiki.php.net/rfc/anonymous_classes
This page keeps coming up in my Internet searches on this subject so figured I should chime in even though this is an 8-year old post. The documentation for PHP5 demonstrates that anonymous classes can be defined within a class method. The object created can extend, implement, and even use other classes, interfaces, and traits. Consider the following OOP paradigm of factory object production. Similar to what #e-i-pi pointed out ...
class Factory {
/**
* Method to manufacture an inner-class object.
*
* #param string $args Arguments to be passed to
* the inner-class constructor.
*/
static function manufacture_object($args) {
/**
* Here's the definition of the inner-class.
*/
return new class($args) {
static $remembers = 'Nothing';
private $args;
function __construct($args) {
$this->$args = $args;
}
function says() {
return $this->args;
}
};
}
}
/**
* Create an inner-class object and have it do its thing.
*/
$mort = Factory::manufacture_object("Hello World!");
echo $mort->says(); // Echoes "Hello World!"
The objects are one-off, so one would expect the static values of the objects returned would not bind from one instance to another. After all, the anonymous class is unique from one object to another. However, late static binding works as one would otherwise expect from a nested class.
$mort = Factory::manufacture_object("I can remember that.");
$mort2 = Factory::manufacture_object("I'll live vicariously through you.");
$mort::$remembers = 'Something';
echo $mort2::$remembers; // Echoes "Something"
So, there you go: inner/nested classes and creation of their objects with static functionality has been possible since September 22, 2013 (right about the time this question was asked).
Put each class into separate files and "require" them.
User.php
<?php
class User {
public $userid;
public $username;
private $password;
public $profile;
public $history;
public function __construct() {
require_once('UserProfile.php');
require_once('UserHistory.php');
$this->profile = new UserProfile();
$this->history = new UserHistory();
}
}
?>
UserProfile.php
<?php
class UserProfile
{
// Some code here
}
?>
UserHistory.php
<?php
class UserHistory
{
// Some code here
}
?>

Categories