php dynamic class inheritance - php

I know I can generate a class at runtime by executing
$obj = (object)array('foo' => 'bar');+
this way I can use
echo $obj->foo; //bar
What if want to make $obj inherits from an existing class?
What I wanna achive:
I'm forking paris project on github (https://github.com/balanza/paris). It's an active record class. I wonder I need to declare a class for every object, even if it's empty:
class User extends Model{}
I guess I might use dynamic object to avoid this boring stuff.

You could always do eval('class User extends Model{}') but is not a good idea. Really, you should just create the class in a file, then opcode caching will work properly, it can be version tracked, etc etc.
tl;dr: Define the model class, it is the Right Thing To Do™.

If there is really no other way for you to do it, you can create a "dynamic" inheritance with my Dynherit class. It creates the inheritance you want but from files and only with classes you didnt already loaded.
Download v0.62 : http://optimisationphp.komrod.com/source/sha/test/dynamic_inheritance_01/dynherit_v0.62.zip
GitHub link : https://github.com/Komrod/Dynherit

Strictly to your question, the only way I can see it possible is by using Runkit, which let's you re-declare classes on the fly. Not sure how portable that solution is.

You can use a Prototype design pattern to clone an object, then you can add everything you need in cloned one

Related

How do I access a subclass's functions using namespaces?

So, I have a few classes I'm trying to use PHP's namespaces with and am having some trouble accessing the functions in the lowest level class.
Here's how it's laid out...
Activity -> Post
Activity has a namespace of activity and Post has a namespace of post
At the top of my Post class I have this code.
namespace Post;
use activity\activity;
That's the code that PHPStorm created when I made my class file and then extended my Activity class.
So, when I try to access my public functions inside Post, I have tried both of these methods...
\activity\post::function();
AND
$post = new \activity\post();
$post->function();
But PHPStorm tells me neither of those exist.
So, what's the actual way to access these lower level functions?
I've googled quite a bit but apparently I'm not searching for the right thing because I haven't found anything about sub classes.
Thanks so much for your help in understanding how this works.
Don't use \activity, use activity.
\activity is using the \ (or base) namespace.
Use doesn't extend a class, it creates an alias. Since you have Use activity\activity this makes it so you can access functions in the activity class by running activity::function() rather than using the full namespace \activity\activity::function().
You can also define use \activity\activity as test and access functions like test::function().
I'm not sure of the point of having the namespaces the same name as the classes though but sjagr addressed that in comments.

PHP workaround to extend classes of the same name?

I know extending a class with the same name is not possible, but I was curious if anyone knew of a way to load a class then rename it, so i can later extend it with the original name. Hopefully like something below:
<?php
//function to load and rename Class1 to Class2: does something like this exist?
load_and_rename_class('Class1', 'Class2');
//now i can extend the renamed class and use the original name:
class Class1 extends Class2{
}
?>
EDIT:
Well, I understand that this would be terrible practice in a basic OOP environment where there are large libraries of class files. But i'm using the CakePHP MVC framework and it would make great sense to be able to extend plugin classes in this way since the framework follows a well established naming convention (Model names, view names, controller names, url routes (http://site.com/users), etc).
As of now, to extend a CakePHP plugin (eg: Users plugin) you have to extend all the model, view, and controller classes each with different names by adding a prefix (like AppUsers) then do some more coding to rename the variable names, then you have to code the renamed url routes, etc. etc. to ultimately get back to a 'Users' name convention.
Since the MVC framework code is well organized it would easily make sense in the code if something like the above is able to be implemented.
I'm trying to work out why this would be necessary. I can only think of the following example:
In a context that you have no control over, an object is initialised:
// A class you can't change
class ImmutableClass {
private function __construct() {
$this->myObject = new AnotherImmutableClass();
}
}
$immutable = new ImmutableClass();
// And now you want to call a custom, currently non existing method on myObject
// Because for some reason you need the context that this instance provides
$immutable->myObject->yourCustomMethod();
And so now you want to add methods to AnotherImmutableClass without editing either Immutable class.
This is absolutely impossible.
All you can do from that context is to wrap that object in a decorator, or run a helper function, passing the object.
// Helper function
doSomethingToMyObject($immutable->myObject);
// Or decorator method
$myDecoratedObject = new objectDecorator($immutable->myObject);
$myDecoratedObject->doSomethingToMyObject();
Sorry if I got the wrong end of the stick.
For more information on decorators see this question:
how to implement a decorator in PHP?.
I happen to understand why you would want to do this, and have come up with a way to accomplish what the end goal is. For everyone else, this is an example of what the author may be dealing with...
Through out a CakePHP application you may have references to helper classes (as an example > $this->Form->input();)
Then at some point you may want to add something to that input() function, but still use the Form class name, because it is through out your application. At the same time though you don't want to rewrite the entire Form class, and instead just update small pieces of it. So given that requirement, the way to accomplish it is this...
You do have to copy the existing class out of the Cake core, but you do NOT make any changes to it, and then when ever you upgrade cake you simply make an exact copy to this new directory. (For example copy lib/Cake/View/Helper/FormHelper.php to app/View/Helper/CakeFormHelper.php)
You can then add a new file called app/View/Helper/FormHelper.php and have that FormHelper extend CakeFormHelper, ie.
App::uses('CakeFormHelper', 'View/Helper');
FormHelper extends CakeFormHelper {
// over write the individual pieces of the class here
}

Why does Codeigniter assume I want to create an instance of the class when using $this->load?

In Codeigniter, when we use $this->load('class_name') in the controller, CI will try to create an instance of the class/model using its constructor.
But sometimes, I don't actually need an instance from that class, I just want to call some static functions from it. Also, there is a big limitation with $this->load('class_name'), it does not allow me to pass parameters to the constructor (unless we extend or modify the core class of CI).
I think the $this->load('class_name') function should only do a require_once on the class php file for me, and let me freely do things (create instance/call static functions) with the class in the controller.
Should I simply ignore this function and use require_once or writing my own __autoload function to load up the classes? This way, I just feel strange because it seems I am not writing codes inside the CI box.
You can pass parameters to your constructor. See the "Passing Parameters When Initializing Your Class" section in the user guide.
I found CodeIgniter's object creation and loading to be very limiting. I want full control over my code, and little magic in the background. I have instead started using Doctrine's Class Loader. It's very lightweight and is essentially SPL autoloading (also a good alternative). You don't need the whole Doctrine shebang with ORM and all that stuff, just the ClassLoader. There's some configuration tinkering to get this right, but it works wonders.
With PHP 5.3 I now have namespaced classes in the Application directory. For instance I created a new class in the Tests directory: Application\Tests\SomeTest.php
That test could look something like this:
namespace Tests;
class SomeTest {
...
}
I would use this class in my code (controllers, views, helpers) by simply using the fully qualified namespace (i.e. $test = new \Tests\SomeTest) or a "use" statement at the top of my code (use \Tests\SomeTest as SomeTest).
In this way I intend to replace all libraries and models with OO namespaced variants. There are many benefits to this: fast autoloading with SPL, full IDE intellisense support for classes/methods (CodeIgniter is really bad for that), your code is more portable to other frameworks or projects.
That said, I still use a lot of the CodeIgniter engine. This basically means I have $CI =& get_instance() in most of my classes. It's still a work in progress and I think the main reason I need CI is for it's database access. If I can factor that out ... and use something like Dependency Injection, then I won't need CodeIgniter in my classes at all. I will simply be using it for it's MVC framework, and using it's methods occasionally in my controllers.
I know this goes above and beyond your question, but hopefully it's some food for though - and it helps me to get it in writing too.

php extending classes

I'm using a salesforce class called SforceEnterpriseClient. I've referenced that class many places in my application. I want to extend that class to give it the ability to return a single array from a 1 row recordset, right now the record set is about 3 levels deep. There's a few other things I want to do with it as well. I can handle all that.
Everything I've read about classes says that when I extend a class, I need to call the new one as such:
class MySF extends SforceEnterpriseClient {};
$mySforceConnection = new $MySF;
That means in all of my existing code I have to find/replace.
Is it possible to overwrite the parent with the child so I don't have to play the find/replace game?
class SforceEnterpriseClient extends SforceEnterpriseClient {};
$mySforceConnection = new $SforceEnterpriseClient ;
You can probably play some classloading tricks with the magic __autoload() function and removing references to the salesforce file ie. require, require_once, include, include_once; But in the interest of readability and maintainability, you should probably take the long route here and modify all your references to use the subclass.
How about this, in the source file for the class, rename the class (and most likely the constructor as well) then extend the class using something like
class SforceEnterpriseClient extends renamedClass {};
Then rename the file and create a new file with the old name and include the renamed file. Put the code for your extended version in the new file. The final result is that every file that was using the original will see the new version without having to track them all down.
About the only major issue would be what happens when a new version of the class becomes available.
Unfortunately, that would be the only way to do so. You cannot reverse inhertiance. Sorry and good luck!
Kyle
Maybe you do not need to extend the class in this scenario. You extend a class when you want to add new functionality or change existing functionality AND keep the original class intact. Usually this is the way to go. But, if you need to make a change to an existing class and then update all references to the class to refer to the new class why not simply change the class code itself? That way the references would not have to change.
Also have a look at the factory pattern. Normally you should keep class creation and business logic separate.
So when you come across a problem like this, you only have to go and change the factory...
$sfEnterpriseClient = Factory::getSFEnterpriseClient($params);
that way you can avoid 'new' constructs in your business logic, and makes your code more manageable

PHP runtime class modification

So I want to be able to add/remove class methods at runtime. Before you tell me that's horrible pratice in oop, it might be, but I don't really care. The reason I want to be able to do this is because I want the application to be very modular, so some plugin could extend some base class and add methods to it without killing the the main app.
For example, say I have the following class:
class User {
protected $Id;
protected $Name;
protected $Password;
protected $PostsPerPage;
}
And say, some plugin adds the possibility for users to change their visibility settings, adding a $Visible property to the class. The class would become:
class User {
protected $Id;
protected $Name;
protected $Password;
protected $PostsPerPage;
protected $Visible;
}
This could be achieved via __get and __set, but the most common implementation is for getting and setting runtime generated properties, and it'd be a hassle to code pseudo getters and setters for each added property, as well as using __set is a no-no in my opinion.
The other idea I had was to store the user settings separately, in another array like $UserVisiblitySettings[userid], but that makes things not as OO as I would like them to be.
Next idea was to make a helper class, something like this:
class UserHelper {
public function SetVisiblity($user_object,value);
}
Then, I could use __get and __set to implement "friend" methods/classes, but that sounds too hackish. If I were to go that way might as well just overload __call, __get and __set. Also I'm not so sure this is good OOP pratice, and it'd look ugly too.
The last idea I had was to have some function to create classes dynamically on runtime by using eval() (this is the only valid use of eval I could come up with too). Basically, get the class definition from a file, do some simple bracket finding to find the class' opening and closing brackets and send it to eval.
Using runkit is out of question, as it is outdated and I'd rather not force the user to install some extension.
When I look up to my ideas, the simplest one and less cpu intensive seems to be to overload _call and add a way for methods to be registered in the class.
Please any thoughts that aren't "don't do this" are appreciated.
RunKit extension can do it (runkit_method_add(), etc.)
However it's an experimental extension and you're already aiming at your foot...
You have other options:
Emulate new fields and methods with __get() and __call()
Use subclassing and Factory pattern (class Plugin extends BaseImplementation and have factory instantiate Plugin instead of BaseImplementation). Zend Plugin Loader does something like this.
It's the solution with least overhead, but also is limited to one plugin extending one class.
Add hooks and use delegation (Strategy pattern) ($this->plugin->onFoo()). There's library for this.
PHP doesn't allow this. It may be a dynamic language in other respects, but the class system is deliberately restrictive. You can either install the runkit extension, which changes the language to allow mocking about with classes at runtime (But then you aren't using plain PHP anymore), or you can use the magic-methods to simulate it.
You can override the class, but I don't know if you can reload it in the same request.
some behavior change can be achieved with mediator design pattern (symfony event dispatcher) but you need to know the extension points in advance, and fire events/messages to be caught by an extending class in the future..
if you can wait for the next request, and clear cache if you have it. I made a tool that might help you.
SourceEditor
Here there are more answers to a similar question too, where I put code examples.
How to generate or modify a PHP class at runtime?

Categories