"__class magic method" (mediating references to class names by a custom code) - php

You can redirect calls to some properties/functions by using __get, __call.
Is there a way to do it for classes?
I would like to convert all mentions of some_class_name in the code to, MY_VERSION_some_class_name (not only for one class, it's a pattern).
This would be easy if methods / properties were the target of this renaming policy.
Can you think of a way to do it for classes in PHP?
Edit: I need this for referencing to different variants of classes in different situations. I need one class name to be resolved to different variants of this class, depending on a condition known at runtime, and persistent through the whole session.
Thanks
p.s.
If you are curious why I want to do this, look at Maintaining variants of an application

You can't convert all mentions of some_class_name in the code to another class. However, you can use variables as class names:
$className = "MyClass";
$obj = new $className;
$className::myMethod();
All you have to do is change the variable and you will be using a different class. If you have to do this for a lot of classes, you might want to create some sort of factory for it.
$factory = System::getFactory();
$obj = $factory->getAuthObj();
Basically, the System class would return a different object based on what class needed to be used for that particular run time.

Aiden's untested approach: variable variables and generating a string:
<?php
$dog = "12";
function getDogClass($myNum)
{
global $dog;
// Do something dynamic here;
$dog = "Dog_" . $myNum;
return "dog";
}
class Dog_13rc1
{
function __construct()
{
printf("Woof!");
}
}
class Dog_12
{
function __construct()
{
printf("Grrrr");
}
}
$myObj = new ${getDogClass('13rc1')}();
?>
As long as the call to getDogClass() returns a string of the name of a variable in scope then you are good.
The output is woof.
This means the only refactoring you need is to find/replace occurences of the class name with that call.
But this is grim. and probably slow. Also, a maintenance/bug-tracking nightmare type of hack.

The magic function you want is __autoload:
function __autoload($class_name) {
// include your special class in here
include $class_name . '.php';
}
Read more here: http://php.net/manual/en/language.oop5.autoload.php

Related

How to tell if a class is an internal class or a user class?

Is there a way in PHP to tell (programmatically, obviously) if a given class is an internal class (such as DateTime) or a user class (class MyClass)?
In case you wonder (and I'm sure you do), this is because ReflectionClass::newInstanceWithoutConstructor() throws an exception when used on internal classes, and as I'm writing a library to deep-copy objects, it must skip these internal classes.
Yes, I could just catch the ReflectionException, but this exception is thrown for other reasons as well (such as a non-existing class), and is not thrown for all system classes. so it's not exactly fulfilling my needs.
A cleaner solution than using shell_exec whould be to use reflection:
$reflection = new ReflectionClass('SomeClass');
if($reflection->isUserDefined()) {
// 'SomeClass' is not an PHP internal
}
Instead of an string ('SomeClass') you can also pass an object. For more information lookup Reflection and
ReflectionClass::isUserDefined() in the PHP Manual
Interesting question, one way I can think is by checking the namespace, for example all of your classes would be defined under namespace MyApp and then check:
if(class_exists('\\DateTime')){
continue;
}
Kind of ugly, I know.
Food for thought, based on Дамян Станчев's suggestion:
You could just run a PHP interpreter via shell_exec() that will spew out get_declared_classes(). Capture the output of that, and you should have a "clean" list of system classes.
Extending Mogria's answer, this one should work just fine (don't give me credit for this though, as it was Mogria's answer that got it right ;-)):
function getUserDefinedClasses() {
return array_filter(get_declared_classes(),
function ($class) {
$reflectionClass = new ReflectionClass($class);
return $reflectionClass->isUserDefined();
});
}
You should be able to imitate the reflection behaviour by extending the class you're trying to copy, and overriding the __construct function:
<?php
class MyClass extends ExtendingClass {
public function __construct() {
/* Override default constructor */
}
}
?>
Which could essentially be made dynamic by using eval:
<?php
function newInstanceWithoutConstructor($class) {
$className = $class . "Extended" . rand(0, 99999999);
while (class_exists($className)) {
$className = $class . "Extended" . rand(0, 99999999);
}
eval("class " . $className . " extends " . $class . " { public function __construct() { } }");
return new $className();
}
$newInstance = newInstanceWithoutConstructor("DateTime");
?>
HOWEVER: Using eval can be useful in this case, but also reveals a rather large security-hole if anything user submitted can be submitted in any way to change the contents of $class. If you understand these limitations, and security implications, you should be able to use this.
Can't you use get_declared_classes() in the beginning of your script, store the data in an array and then do an array_diff() with the stored data and the response from get_declared_classes() and check if the class you're checking is in the difference using in_array() ?
This example prints out all the classes with your classes seeming to be at the end of the list. Maybe this can help.
What about storing calling get_declared_classes() data before any autoloading/include/require is made and later checking class name in this storage?

Manipulate PHP-instanceof-operator for wrapper-class

I'd like to have a generic wrapper-class for some classes to intercept and manipulate some of the method-calls. Method-call-forwarding, intercepting, no problem so far. But after thinking a while, i found a problem for which i have no solution: I'm using the built-in instanceof-operator everywhere in my application. Of course this won't work anymore, because the wrapper isn't an instance of the class inside it. I would like to continue using the operator and not to replace it with an other function.
Is there a way to implement a workaround for this problem? How does this operator work? Does it call a core-function of the classes which i am probably able to overwrite in my wrapper?
I know that this would not be a really "clean" solution to manipulate this operator, but i think this would be the simplest solution for me. And as we know, there are many things in PHP which are not that clean... :-)
Thanks for your answers, Ben
I don't know is it possible to trick a instanceof operator in way you want (recognize a class as subclass if it is not) but I think I found a solution that may suit your needs. If I understand correctly your problem then you simply want to inject some methods in any class with minimal changes in your whole code.
I think the best way to prepare a solution in this case is using traits (described here). With traits you can add methods to any class without direct inheritance and it can overwrite methods from base class. For overwriting method with traits you of course need a subclasses but they can be created dynamically. I don't know anything about your wrapping process but in my solution I used a special class for it. Lets look at my solution:
namespace someNameSpace;
//this is one of your class that you want to wrap - it can be declare under some other namespace if you need
class yourBaseClass { }
//your wrapper class as a trait
trait yourWrapper { }
//class for wrapping any object
class ObjectWrapperClass
{
//method for change object class (described on http://stackoverflow.com/a/3243949/4662836)
protected static function objectToObject($instance, $className)
{
return unserialize(sprintf('O:%d:"%s"%s', strlen($className), $className, strstr(strstr(serialize($instance), '"'), ':')));
}
//wrapping method
//$object is a object to be wrapped
//$wrapper is a full name of the wrapper trait
public static function wrap($object, $wrapper)
{
//take some information about the object to be wrapped
$reflection = new \ReflectionClass($object);
$baseClass = $reflection->getShortName();
$namespace = $reflection->getNamespaceName();
//perpare the name of the new wrapped class
$newClassName = "{$baseClass}Wrapped";
//if new wrapped class has not been declared before we need to do it now
if (!class_exists($newClassName)) {
//prepare a code of the wrapping class that inject trait
$newClassCode = "namespace {$namespace} { class {$newClassName} extends {$baseClass} { use {$wrapper}; } }";
//run the prepared code
eval($newClassCode);
}
//change the object class and return it
return self::objectToObject($object, $namespace . '\\' . $newClassName);
}
}
//lets test this solution
$originalObject = new yourBaseClass();
$wrappedObject = ObjectWrapperClass::wrap($originalObject, 'yourWrapper');
if ($wrappedObject instanceof yourBaseClass) {
echo 'It is working';
}
As you can see everything is happens during wrapping process.
If you have more wrappers then you can prepare the new wrapped class name in other way (for example to be corelated with wrapper name).
Probably I can describe a solution for your needs. (disclaimer: I'm author of Go! AOP Framework) From your description it looks like you want to dynamically add additional logic to your methods without touching the class. If I'm right, then you could have a look at Aspect-Oriented Paradigm that introduces a concept of interceptors for your source code, what is more important - your original classes will be untouched.
To have an idea, how this can be applied to your code, you could also have a look at my article http://go.aopphp.com/blog/2014/10/19/caching-like-a-pro/ that highlights all advantages and disadvantages of classical object-oriented patterns like decorator, proxy. I can make a conclusion, that all interceptors can not be extracted into separate modules in object-oriented way because of essential complexity and limitations of PHP for solving cross-cutting concerns. AOP extends traditional OOP model, so it will be possible to extract interceptors (called advices) into separate classes (called aspects).
Brilliant feature of AOP is that it keeps your original class names and this means that you shouldn't change typehints in your code or even hijack a instanceof operator. You will get your class with additional logic.
Not possible at all. Actually, maybe in the future: https://bugs.php.net/bug.php?id=71352
Use an interface instead of the concrete class. Apply the interface to Wrapper and Concrete Class.
See http://de3.php.net/manual/en/language.oop5.interfaces.php
Have a look at decorator pattern. If your wrapper/wrapped classes implement the same interface, you can do everything elegantly (and use instanceof interface throughout the code).
Is there a way to implement a workaround for this problem? How does this operator work? Does it call a core-function of the classes which i am probably able to overwrite in my wrapper?
You cannot manipulate instanceof operator. Since you were interested how instanceof operator is implemented, here is a PHP representation of original C code:
class php_class {
public $interfaces = array(); // array of php_class objects (php classes can implement more than one interface)
public $parent = null; // php_class object (php classes can only extend one class)
}
function instanceof_operator($implementation, $abstraction) {
// forward recursion (iterates recursively through interfaces until a match is found)
for($i=0; $i<count($implementation->interfaces); $i++) {
if(instanceof_operator($implementation->interfaces[$i], $abstraction)) {
return true;
}
}
// backward recursion (iterates recursively through parents until a match is found)
while($implementation!=null) {
if($implementation == $abstraction) {
return true;
}
$implementation = $implementation->parent;
}
// no match was found
return false;
}
Whenever you declare a class to implement/extend an interface/class, imagine an entry is deposited on $interfaces or $parent fields that remains immutable until script terminates.

php: Class lazy-loading?

I have a problem here, which I have been thinking about for the past few days.
In a php application to do something with a object you need to:
define it
run a function with it
like so:
(with autoloading, and a registry object)
$registry->obj = new mathClass($var1,$var2); //creates object where $var1 holds the a database object, and $var2 holds the value 1 for example
$registry->obj->calculate('value'); //fetches product rows and returns their total value.
This way at any time in the script i can simply run the calculate function (or some other function) that I defined beforehand.
Imagine a web application that has hundreds of classes that might or might not be required for this specific page load, but can only be defined at the start of the application.
The desired solution is that I simply run
$obj->calculate('price');
without creating the object, for example like this
mathclass::calculate('price');
this then autoloads the mathclass as required without having the principal overhead, the problem here is that I can no longer give the mathclass any variables at the start
($var1,$var2).
What I want is to be able to pseudo-create the object without any autoloading of the class happening, as to not add the overhead, but that the object creates itself with the variables but only when I actually need to do something with it.
I mean does php really expect me to define each and every class at the start so that I can later use them?
is this Lazy-loading? Eager loading?
I might be explaining this badly so please point me in the right direction.
Edit 2015: Simple pseudocode example solution:
class Service {
private $cb, $instance;
public function __construct($cb){
$this->cb = $cb;
}
public function __invoke() {
if(!$this->instance){
$this->instance = call_user_func($this->cb);
}
return $this->instance;
}
}
// setup autoloading
set_include_path(__DIR__.'/vendor'. PATH_SEPARATOR .get_include_path()); // optional
spl_autoload_register(function($c){
include preg_replace('#\\\|_(?!.+\\\)#','/',$c).'.php';
});
// simple dependency injection
$service['db'] = new Service(function(){
return new Database('sqlite::filename.sqlite');
});
$service['config'] = function() use(&$service){
return new Config($service['db']());
};
$service['math'] = function() use(&$service){
return new Math($service['config']());
};
// usage
$service['math']()->calculate('price');
Use a Dependency Injection Framework. It lets you configure your classes from config files and when you need a class you simply call it through the service builder.
You can use a lazy loading factory, i.e.
class Registry
{
private $registeredClasses;
private $loadedClasses;
private $objects;
public function RegisterClass($className, array $parameters)
{
// ... store class ...
}
private function Load($className)
{
// Load the class via some sort of autoloader
}
private function CreateInstance($className)
{
$parameters = $this->GetParametersFor($className);
$this->CreateNewInstanceWithParameters($className, $parameters);
}
public function GetObject($className)
{
if (!$this->IsAvailable($className))
{
$this->Load($className);
$this->CreateInstance($className);
}
return $this->GetInstanceOf($className);
}
}
Later in your code you use it like this:
$registry = new Registry();
$registry->RegisterClass("math", array("var1" => $var1, "var2" => $var2));
...
$registry->GetObject("math")->calculate($x1, $x2);
...
Ofc you need to add the parts i was too lazy to add, i.e. the autoloading.
if you use the autoload functionality it will only load the math class when you instantiate it, 1 option is to instantiate it when you need it, another option is to use some kind of wrapper class that will include and call the class.
What you can use is Static classes in PHP. Although this is something you might consider not doing for high-traffic websites.
Declare a class like so:
class Something
{
private static $var = "something";
public static function PrintVar()
{
echo self::$var;
}
}
Now you can include this class and execute the code anywhere you like without initializing the object.
Like so:
Something::PrintVar();
prints
something
Good luck!
Part of the reason why class objects require defining using new() is because they consume memory. Normally PHP will perform memory cleanup at the end of script if you havent done so, but usually in a constructor/destructor object-oriented environment you would want to unset() that class object to free up memory. Earlier versions of PHP (before php4) had issues with memory leaks due to these reasons.
If you want to avoid the whole initialization process you may just want to try a simple include library, such as this:
<?
if (!function_exists("calculate"))
{
function calculate($var1={default},$var2={default})
{
...routine...
}
}
?>
And then you do not have to deal with the whole pain of defining a full class for a simple routine.

How to avoid using PHP global objects?

I'm currently creating blog system, which I hope to turn into a full CMS in the future.
There are two classes/objects that would be useful to have global access to (the mysqli database connection and a custom class which checks whether a user is logged in).
I am looking for a way to do this without using global objects, and if possible, not passing the objects to each function every time they are called.
You could make the objects Static, then you have access to them anywhere. Example:
myClass::myFunction();
That will work anywhere in the script. You might want to read up on static classes however, and possibly using a Singleton class to create a regular class inside of a static object that can be used anywhere.
Expanded
I think what you are trying to do is very similar to what I do with my DB class.
class myClass
{
static $class = false;
static function get_connection()
{
if(self::$class == false)
{
self::$class = new myClass;
}
return self::$class;
}
// Then create regular class functions.
}
What happens is after you get the connection, using $object = myClass::get_connection(), you will be able to do anything function regularly.
$object = myClass::get_connection();
$object->runClass();
Expanded
Once you do that static declarations, you just have to call get_connection and assign the return value to a variable. Then the rest of the functions can have the same behavior as a class you called with $class = new myClass (because that is what we did). All you are doing is storing the class variable inside a static class.
class myClass
{
static $class = false;
static function get_connection()
{
if(self::$class == false)
{
self::$class = new myClass;
}
return self::$class;
}
// Then create regular class functions.
public function is_logged_in()
{
// This will work
$this->test = "Hi";
echo $this->test;
}
}
$object = myClass::get_connection();
$object->is_logged_in();
You could pass the currently global objects into the constructor.
<?php
class Foo {
protected $m_db;
function __construct($a_db) {
$this->m_db = $a_db;
}
}
?>
I recently revamped my framework in preparation for the second version of our company's CMS. I undid a huge amount of the things I made static in order to replace them with normal objects. In so doing, I created a huge amount of flexibility that used to rely on me going through and hacking into core files. I now only use static constructs when the only alternative is global functions, which is only related to low-level core functionality.
I'm going to show a few lines of my bootstrap.php file (all of my requests get sent through that file, but you can achieve the same result by including it at the top of every file) to show you what I mean. This is an pretty hefty version of what you'd probably use in your situation, but hopefully the idea is helpful. (This is all slightly modified.)
//bootstrap.php
...
// CONSTRUCT APPLICATION
{
$Database = new Databases\Mysql(
Constant::get('DATABASE_HOST'),
Constant::get('DATABASE_USER'),
Constant::get('DATABASE_PASSWORD'),
Constant::get('DATABASE_SCHEMA')
);
$Registry = new Collections\Registry;
$Loader = new Loaders\Base;
$Debugger = new Debuggers\Dummy; // Debuggers\Console to log debugging info to JavaScript console
$Application = new Applications\Base($Database, $Registry, $Loader, $Debugger);
}
...
As you can see, I have all kind of options for creating my application object, which I can provided as an argument in the constructor to other objects to give them access to these "global" necessities.
The database object is self-explanatory. The registry object acts as a container for object I may want to access elsewhere in the application. The loader acts as a utility for loading other resources like template files. And the debugger is there to handle debug output.
I can, for example, change the database class that I instantiate and, voila I have a connection to a SQLite database. I can change the class of the debugger (as noted) and now all of my debug info will be logged to my JavaScript console.
Okay, now back to the issue. How do you give other objects access to all of this? You simply pass it in an argument to the constructor.
// still bootstrap.php
...
// DISPATCH APPLICATION
{
$Router = new Routers\Http($Application);
$Router->routeUri($_SERVER['REQUEST_URI']);
}
...
Not only that, but my Router (or whatever object I construct with it) is more flexible, too. Now I can just instantiate my application object differently, and my Router will behave differently accordingly.
Well, if you already have some object by which you refer to the blog system, you can compose these objects into that, so that they're $blog->db() and $blog->auth() or whatever.

When do/should I use __construct(), __get(), __set(), and __call() in PHP?

A similar question discusses __construct, but I left it in my title for people searching who find this one.
Apparently, __get and __set take a parameter that is the variable being gotten or set. However, you have to know the variable name (eg, know that the age of the person is $age instead of $myAge). So I don't see the point if you HAVE to know a variable name, especially if you are working with code that you aren't familiar with (such as a library).
I found some pages that explain __get(), __set(), and __call(), but I still don't get why or when they are useful.
This page will probably be useful. (Note that what you say is incorrect - __set() takes as a parameter both the name of the variable and the value. __get() just takes the name of the variable).
__get() and __set() are useful in library functions where you want to provide generic access to variables. For example in an ActiveRecord class, you might want people to be able to access database fields as object properties. For example, in Kohana PHP framework you might use:
$user = ORM::factory('user', 1);
$email = $user->email_address;
This is accomplished by using __get() and __set().
Something similar can be accomplished when using __call(), i.e. you can detect when someone is calling getProperty() and setProperty() and handle accordingly.
__get(), __set(), and __call() are what PHP calls "magic methods" which is a moniker I think that is a bit silly - I think "hook" is a bit more apt. Anyway, I digress...
The purpose of these is to provide execution cases for when datamembers (properties, or methods) that are not defined on the object are accessed, which can be used for all sorts of "clever" thinks like variable hiding, message forwarding, etc.
There is a cost, however - a call that invokes these is around 10x slower than a call to defined datamembers.
Another useful application of magic methods, especially __get and __set and __toString is templates. You can make your code independent from template engine just by writing simple adapter that uses magic methods. In case you want to move to another template engine, just change these methods only.
class View {
public $templateFile;
protected $properties = array();
public function __set($property, $value) {
$this->properties[$property] = $value;
}
public function __get($property) {
return #$this->properties[$property];
}
public function __toString() {
require_once 'smarty/libs/Smarty.class.php';
$smarty = new Smarty();
$smarty->template_dir = 'view';
$smarty->compile_dir = 'smarty/compile';
$smarty->config_dir = 'smarty/config';
$smarty->cache_dir = 'smarty/cache';
foreach ($this->properties as $property => $value) {
$smarty->assign($property, $value);
}
return $smarty->fetch($this->templateFile);
}
}
Hidden benefit of this approach is that you can nest View objects one inside another:
$index = new View();
$index->templateFile = 'index.tpl';
$topNav = new View();
$topNav->templateFile = 'topNav.tpl';
$index->topNav = $topNav;
And in index.tpl, the nesting looks like that:
<html>
<head></head>
<body>
{$topNav}
Welcome to Foobar Corporation.
</body>
</html>
All nested View objects gets converted to string (HTML to be exact) on the fly, as soon as you echo $index;
Redefining __get and __set can be especially useful in core classes. For example if you didn't want your config to be overwritten accidentally but still wanted to get data from it:
class Example
{
private $config = array('password' => 'pAsSwOrD');
public function __get($name)
{
return $this->config[$name];
}
}
I think it is bad for design you code. If you know and do a good design then you will not need to use the __set() and __get() within your code. Also reading your code is very important and if you are using studio (e.g. Zend studio), with __set() and __get() you can't see your class properties.
PHP allows us to create class variables dynamically which can cause problems. You can use __set and __get methods to restrict this behavior..see the example below...
class Person {
public $name;
public function printProperties(){
print_r(get_object_vars($this));
}
}
$person = new Person();
$person->name = 'Jay'; //This is valid
$person->printProperties();
$person->age = '26'; //This shouldn't work...but it does
$person->printProperties();
to prevent above you can do this..
public function __set($name, $value){
$classVar = get_object_vars($this);
if(in_array($name, $classVar)){
$this->$name = $value;
}
}
Hope this helps...
They're for doing "clever" things.
For example you could use __set() and __get() to talk to a database. Your code would then be: $myObject->foo = "bar"; and this could update a database record behind the scenes. Of course you'd have to be pretty careful with this or your performance could suffer, hence the quotes around "clever" :)
Overloading methods is especially useful when working with PHP objects that contain data that should be easily accessable. __get() is called when accessing a non-existent propery, __set() is called when trying to write a non-existent property and __call() is called when a non-existent method is invoked.
For example, imagine having a class managing your config:
class Config
{
protected $_data = array();
public function __set($key, $val)
{
$this->_data[$key] = $val;
}
public function __get($key)
{
return $this->_data[$key];
}
...etc
}
This makes it a lot easier to read and write to the object, and gives you the change to use custom functionality when reading or writing to object.
Example:
$config = new Config();
$config->foo = 'bar';
echo $config->foo; // returns 'bar'
One good reason to use them would be in terms of a registry system (I think Zend Framework implements this as a Registry or Config class iirc), so you can do things like
$conf = new Config();
$conf->parent->child->grandchild = 'foo';
Each of those properties is an automatically generated Config object, something akin to:
function __get($key) {
return new Config($key);
}
Obviously if $conf->parent already existed, the __get() method wouldn't be called, so to use this to generate new variables is a nice trick.
Bear in mind this code I've just quoted isn't functionality, I just wrote it quickly for the sake of example.
Probably not the cleanest design in the world but I had a situation where I had a lot of code that was referencing an instance variable in a class, i.e.:
$obj->value = 'blah';
echo $obj->value;
but then later, I wanted to do something special when "value" was set under certain circumstances so I renamed the value variable and implemented __set() and __get() with the changes I needed.
The rest of the code didn't know the difference.

Categories