I'm creating a dynamic class that responds to magic __call() method. The problem is, since I'm building this on top of a already existing framework (Kohana), it checks if the method of the class exists using ReflectionClass::hasMethod, and it doesn't seem to trigger the __call() magic method for checking for it's existance. What could I do in this case? Seems like if you add the method dynamically (like $this->{$name} = function(){}) it still can't "see" it
Without more details, I'm unsure if this would suffice, however you could create proxy class to perform intermediate functionality:
class MyProxy {
protected $_object = null;
protected $_methods = array();
public function __construct($object) {
if (!is_object($object)) {
throw new InvalidArgumentException('$object must be an object');
}
$this->_object = $object;
}
public function __call($name, $arguments) {
return $this->callMethod($name, $arguments);
}
public function setMethod($name, Closure $method) {
$this->_methods[(string) $key] = $method;
}
public function callMethod($name, array $arguments) {
if (isset($this->_methods[$name])) {
return call_user_func_array($this->_methods[$name], $arguments);
}
return call_user_func_array(array($this->_object, $name), $arguments);
}
}
By calling $proxy->setMethod('foo', function () { });, you can dynamically "attach" methods to the object. When you call $proxy->foo(), it'll first do a look-up against the dynamically attached methods; if it finds one, it'll call it. Otherwise, it'll just delegate to the internal object.
Now, the problem with this approach is that attached methods aren't bound to the proxy. In other words, $this doesn't exist in the scope of an attached method.
This can be fixed though, with features from PHP 5.4+.
public function setMethod($name, Closure $method) {
$this->_methods[(string) $name] = Closure::bind($method, $this);
}
We've refined setMethod to rebind the passed closure to the proxy. Now, in the scope of an attached method, $this will point to the proxy object.
We could have rebound it to the enclosed object, but then the attached methods couldn't talk to the proxy (or other attached methods). For completeness, you'll want to add __get and __set magic, to forward property access/mutate calls to the internal object (or handle them in the proxy, whatever)
Besides, the internal object has no clue about the proxy, so it's methods (from the class definition) won't know about any of this dynamic magic anyway.
Seems like if you add the method dynamically (like $this->{$name} = function(){}) it still can't "see" it
Right, as you're creating a new property, not a method. At time of writing, PHP did not support calling anonymous functions in properties without going through __call, which isn't Reflection-friendly. Properties-with-anonymous-functions-as-methods work properly in PHP 5.4.
The only other way to add a method to a class in a way that Reflection will pick up on is using the highly experimental "runkit" extension.
Related
I don't have high hopes for this one:
Given a service that has an action like the foo in $service->foo->bar( $a, $b ) and a container class that has $service as a protected property, is there a way to use __get() on the container to access the service and pass along the ->bar( $a, $b )?
class Container {
protected $service;
protected $responses = [];
public function __get ($name) {
$this->responses[] = $service->$name-> _???_
return $resp;
}
}
that could be intercepted so that the Container could catch the operation, call $service with it, save the response, then return the response
Either some way to grab whatever else is being chained on the $name or if $name just included all of that. I know this is a little convoluted, but it would help me clean some code up substantially, plus I'm just generally curious now.
This app is running PHP7 if that matters.
And alternately, if there is a way to do this but it isn't __get(), insight would be appreciated
The call to bar takes place after __get returned. __get is called by the engine so you can't add additional parameters. However you can create additional methods on your container class to implement the feature you want.
Assuming I understood your question correctly this would result in something like this:
public function executeOnService(string $name, string $method, ...$args) {
return call_user_func_array([$this->service->$name, $method], $args);
}
Since you already expect the consumer code of your Container to know a lot about the properties of this service object, perhaps you should just consider returning the property of the service that the consuming code wants to act upon, e.g.:
public function __get ($name) {
return $service->$name;
}
Here is a function definition of Set Helper class
public function singleton($key, $value)
{
$this->set($key, function ($c) use ($value) {
static $object;
if (null === $object) {
$object = $value($c);
}
return $object;
});
}
and in this class the above mentioned function will be called like
// Default environment
$this->container->singleton('environment', function ($c) {
return \Slim\Environment::getInstance();
});
where $this->container represents the Set helper class.
This appears to be an example of singleton factory using a plugin-strategy.
The API user declares "When I ask for the environment object, use the function function ($c) { return Slim\Environment::getInstance() } to generate it." The singleton method then takes care to ensure the API user only ever gets back the single instance of the environment object.
Mechanically, the singleton method associates a closure with a key. The closure manufactures a singleton object, given an anonymous function plug-in to actually do the instantiation. $value is the anonymous function and is responsible for whatever needs to go on to generate an instance of the object to become a singleton. singleton is responsible for ensuring that instantiation is every called once.
Side note: the difference between a closure and an anonymous function is meaninful in understanding what's going on with this method.
I know the following could potentially create problems elsewhere and is probably bad design, but I still would like to know why this fails (for my own edification):
class Test {
// singleton
private function __construct(){}
private static $i;
public static function instance(){
if(!self::$i){
self::$i = new Test();
}
return self::$i;
}
// pass static requests to the instance
public static function __callStatic($method, $parameters){
return call_user_func_array(array(self::instance(), $method), $parameters);
}
private $someVar = 1;
public function getSomeVar(){
return $this->someVar;
}
}
print Test::getSomeVar();
The error is Using $this when not in object context
Obviously $this is unavailable from a static method, but the static method is handing it off to an instance method invokation via call_user_func_array, which should make $this the instance...
/EDIT
I'm aware that $this is not available in static context. However, this works:
print call_user_func_array(array(Test::instance(), 'getSomeVar'), array());
Which is exactly what's happening in the __callStatic overload, so something's amiss...
/EDIT 2
scope is definitely getting handled strangely. if you pull the singleton instance to any other class, it works as expected:
class Test {
// singleton
private function __construct(){}
private static $i;
public static function instance(){
if(!self::$i){
self::$i = new Blah();
}
return self::$i;
}
// pass static requests to the instance
public static function __callStatic($method, $parameters){
return call_user_func_array(array(static::instance(), $method), $parameters);
}
}
class Blah {
private $someVar = 1;
public function getSomeVar(){
return $this->someVar;
}
}
print Test::getSomeVar();
You can not staticfy your object methods through __callStatic calls in PHP. It will only be invoked when the method so far does not exist (incl. not being visible from the calling context). In your case Test::getSomeVar() is already defined.
Because of backwards compatibility, PHP does not check if only a static method exists, but actually if generally a method exists.
In your case you are calling the non-static method statically, so $this is not defined because __callStatic has not been invoked. If you would have enabled warnings and notices to the highest level (recommended for development), PHP would have warned you about that.
The correct usage therefore is:
echo Test::instance()->getSomeVar();
As with any other implementation of a Singleton.
So you are just using __callStatic wrong, it only works for methods not yet defined. Choose another tool/design for the job, like the aggregation example you use with your Blah class.
A further note:
You should normally prevent to use any static context in PHP anyway, especially as you exploit a lot of magic functionality here, too, which is another smell. It looks like you have a pile of design issues before you even finished your code. You will only increase the likelihood to run into hard to debug and maintain code with all this. But that just so you do not say in some time you have not been warned.
See Who needs singletons? in case you want to learn more.
It doesn't work like that. In a static call you have no instance, no object and no $this. Call static only works with static methods in which $this is unavailable.
The documentation says:
__callStatic() is triggered when invoking inaccessible methods in a static context.
I know this is not the answer you were hoping for. As you have anticipated: you don't need of overloading in PHP, just create your app and leave this thing out.
An ethical question here.
I'm planning on using several manager classes in my new project that will be performing various tasks across the whole project. These classes are singletons, but require construction based on parameters.
As to when/where this construction has to happen, I have mixed feelings. I have these options so far:
Option A
It's easy to just pass these parameters to the getInstance method while having a default null value. On the very first call the parameters will be used, and any additional calls completely ignore them.
While this works, doing so feels rather unlogical, for the following reasons:
It makes documentation unclear. getInstance' first parameter must be of type Collection, but can be null... what's going on here?
You can argue that writing a line about this in the description will clear it up, but I'd prefer clarification to be unneccesary.
It feels faulty to pass getInstance any construction parameters. This is due to the fact that the method name does not explicity hint towards construction, making it unclear it will happen.
Option B
I'm thinking about a setup method. This method takes all parameters, calls the class constructor, and changes the internal class state to initialized.
When calling the getInstance method prior to setup, it will throw a NotInitializedException. After setup has been called, any additional calls to setup will result in a PreviouslyInitializedException.
After setup has been called, getInstance becomes available.
Personally, this option appeals more to me. But it feels excessive.
What option do you prefer? And why?
I would probably try and ditch the singleton approach and pass manager classes around to whatever needs them.
$manager = new Manager( $collection, $var, $var2 );
$other_class = New OtherClass( $manager );
//or
$other_class = New OtherClass;
$other_class->manager = $manager;
//or
$other_class = New OtherClass;
$other_class->setManager( $manager );
Use dependency injection to pass the Manager object around. Don't use Singleton pattern. It's a common consensus that using it creates a global state and makes your API deceptive.
PHP Global in functions (jump to answer)
Singletons are pathological liars
Inject the Manager instance to any class that needs it via the constructor. Each class should not try to instantiate Manager by themselves, the only way the classes get an instance of the Manager is by getting it from constructor.
class NeedsManager
{
protected $manager;
public function __construct(Manager $manager)
{
$this->manager = $manager;
}
}
You don't need to enforce one instance of Manager. Just don't instantiate it more than once. If all of your classes that need an instance of Manager get what they need from the constructor and never tries to instantiate it on their own, it will assure that there's just going to be one instance in your application.
How about option 3. If they are true singletons, set up properties files for their parameters for use with a no-arg getInstance.
If that doesn't fit, you might be misusing the singleton pattern.
You are looking at using a Factory design pattern. Factories are objects that act as fancy constructors for other objects. In your case, you will move setup and getInstance to the factory. The wiki article's pretty good- http://en.wikipedia.org/wiki/Factory_method_pattern
class SingletonFoo {
//properties, etc
static $singleton = NULL;
private function __constructor(){}
static function getInstance(){
if(NULL === self::$singleton) {
self::$singleton = new SingletonFoo();
}
return self::$singleton;
}
}
class FooFactory {
static $SingletonFoo = null;
static function setup($args){
if( !(NULL === self::$SingletonFoo)){
throw new AlreadyInstantiatedException();
}
self::$SingletonFoo = SingletonFoo::getInstance();
//Do stuff with $args to build SingletonFoo
return self::$SingletonFoo;
}
static function getInstance(){
if(NULL === self::$SingletonFoo) {
throw new NotInstantiatedException();
}
return self::$SingletonFoo;
}
}
Don't use Singleton, use Resources Manager (or Service Container, or DI Container):
class ResourceManager
{
protected static $resource;
public static function setResource($resource)
{
if (!empty(self::$resource)) //resource should not be overwritten
{
if ($resource!=self::$resource) return false;
else return true;
}
self::$resource = $resource;
return true;
}
public static function getResource()
{
return self::$resource;
}
}
Resource Manager allows you to set any custom classes for unit-testing (like dependency injection), you can just get needed resources without requesting them in constructor (I like DI, but sometimes it's just more handy to use empty constructors).
Ready-to-use variant: http://symfony.com/doc/current/book/service_container.html (I don't like to move logic from code to configs, but in stand-alone module it looks acceptable).
I'm going to try something with the format of this question and I'm very open to suggestions about a better way to handle it.
I didn't want to just dump a bunch of code in the question so I've posted the code for the class on refactormycode.
base class for easy class property handling
My thought was that people can either post code snippets here or make changes on refactormycode and post links back to their refactorings. I'll make upvotes and accept an answer (assuming there's a clear "winner") based on that.
At any rate, on to the class itself:
I see a lot of debate about getter/setter class methods and is it better to just access simple property variables directly or should every class have explicit get/set methods defined, blah blah blah. I like the idea of having explicit methods in case you have to add more logic later. Then you don't have to modify any code that uses the class. However I hate having a million functions that look like this:
public function getFirstName()
{
return $this->firstName;
}
public function setFirstName($firstName)
{
return $this->firstName;
}
Now I'm sure I'm not the first person to do this (I'm hoping that there's a better way of doing it that someone can suggest to me).
Basically, the PropertyHandler class has a __call magic method. Any methods that come through __call that start with "get" or "set" are then routed to functions that set or retrieve values into an associative array. The key into the array is the name of the calling method after getting or setting. So, if the method coming into __call is "getFirstName", the array key is "FirstName".
I liked using __call because it will automatically take care of the case where the subclass already has a "getFirstName" method defined. My impression (and I may be wrong) is that the __get & __set magic methods don't do that.
So here's an example of how it would work:
class PropTest extends PropertyHandler
{
public function __construct()
{
parent::__construct();
}
}
$props = new PropTest();
$props->setFirstName("Mark");
echo $props->getFirstName();
Notice that PropTest doesn't actually have "setFirstName" or "getFirstName" methods and neither does PropertyHandler. All that's doing is manipulating array values.
The other case would be where your subclass is already extending something else. Since you can't have true multiple inheritances in PHP, you can make your subclass have a PropertyHandler instance as a private variable. You have to add one more function but then things behave in exactly the same way.
class PropTest2
{
private $props;
public function __construct()
{
$this->props = new PropertyHandler();
}
public function __call($method, $arguments)
{
return $this->props->__call($method, $arguments);
}
}
$props2 = new PropTest2();
$props2->setFirstName('Mark');
echo $props2->getFirstName();
Notice how the subclass has a __call method that just passes everything along to the PropertyHandler __call method.
Another good argument against handling getters and setters this way is that it makes it really hard to document.
In fact, it's basically impossible to use any sort of document generation tool since the explicit methods to be don't documented don't exist.
I've pretty much abandoned this approach for now. It was an interesting learning exercise but I think it sacrifices too much clarity.
The way I do it is the following:
class test {
protected $x='';
protected $y='';
function set_y ($y) {
print "specific function set_y\n";
$this->y = $y;
}
function __call($function , $args) {
print "generic function $function\n";
list ($name , $var ) = split ('_' , $function );
if ($name == 'get' && isset($this->$var)) {
return $this->$var;
}
if ($name == 'set' && isset($this->$var)) {
$this->$var= $args[0];
return;
}
trigger_error ("Fatal error: Call to undefined method test::$function()");
}
}
$p = new test();
$p->set_x(20);
$p->set_y(30);
print $p->get_x();
print $p->get_y();
$p->set_z(40);
Which will output (line breaks added for clarity)
generic function set_x
specific function set_y
generic function get_x
20
generic function get_y
30
generic function set_z
Notice: Fatal error: Call to undefined method set_z() in [...] on line 16
#Brian
My problem with this is that adding "more logic later" requires that you add blanket logic that applies to all properties accessed with the getter/setter or that you use if or switch statements to evaluate which property you're accessing so that you can apply specific logic.
That's not quite true. Take my first example:
class PropTest extends PropertyHandler
{
public function __construct()
{
parent::__construct();
}
}
$props = new PropTest();
$props->setFirstName("Mark");
echo $props->getFirstName();
Let's say that I need to add some logic for validating FirstNames. All I have to do is add a setFirstName method to my subclass and that method is automatically used instead.
class PropTest extends PropertyHandler
{
public function __construct()
{
parent::__construct();
}
public function setFirstName($name)
{
if($name == 'Mark')
{
echo "I love you, Mark!";
}
}
}
I'm just not satisfied with the limitations that PHP has when it comes to implicit accessor methods.
I agree completely. I like the Python way of handling this (my implementation is just a clumsy rip-off of it).
Yes that's right the variables have to be manually declared but i find that better since I fear a typo in the setter
$props2->setFristName('Mark');
will auto-generate a new property (FristName instead of FirstName) which will make debugging harder.
I like having methods instead of just using public fields, as well, but my problem with PHP's default implementation (using __get() and __set()) or your custom implementation is that you aren't establishing getters and setters on a per-property basis. My problem with this is that adding "more logic later" requires that you add blanket logic that applies to all properties accessed with the getter/setter or that you use if or switch statements to evaluate which property you're accessing so that you can apply specific logic.
I like your solution, and I applaud you for it--I'm just not satisfied with the limitations that PHP has when it comes to implicit accessor methods.
#Mark
But even your method requires a fresh declaration of the method, and it somewhat takes away the advantage of putting it in a method so that you can add more logic, because to add more logic requires the old-fashioned declaration of the method, anyway. In its default state (which is where it is impressive in what it detects/does), your technique is offering no advantage (in PHP) over public fields. You're restricting access to the field but giving carte blanche through accessor methods that don't have any restrictions of their own. I'm not aware that unchecked explicit accessors offer any advantage over public fields in any language, but people can and should feel free to correct me if I'm wrong.
I've always handled this issue in a similar with a __call which ends up pretty much as boiler plate code in many of my classes. However, it's compact, and uses the reflection classes to only add getters / setters for properties you have already set (won't add new ones). Simply adding the getter / setter explicitly will add more complex functionality. It expects to be
Code looks like this:
/**
* Handles default set and get calls
*/
public function __call($method, $params) {
//did you call get or set
if ( preg_match( "|^[gs]et([A-Z][\w]+)|", $method, $matches ) ) {
//which var?
$var = strtolower($matches[1]);
$r = new ReflectionClass($this);
$properties = $r->getdefaultProperties();
//if it exists
if ( array_key_exists($var,$properties) ) {
//set
if ( 's' == $method[0] ) {
$this->$var = $params[0];
}
//get
elseif ( 'g' == $method[0] ) {
return $this->$var;
}
}
}
}
Adding this to a class where you have declared default properties like:
class MyClass {
public $myvar = null;
}
$test = new MyClass;
$test->setMyvar = "arapaho";
echo $test->getMyvar; //echos arapaho
The reflection class may add something of use to what you were proposing. Neat solution #Mark.
Just recently, I also thought about handling getters and setters the way you suggested (the second approach was my favorite, i.e. the private $props array), but I discarded it for it wouldn't have worked out in my app.
I am working on a rather large SoapServer-based application and the soap interface of PHP 5 injects the values that are transmitted via soap directly into the associated class, without bothering about existing or non-existing properties in the class.
I can't help putting in my 2 cents...
I have taken to using __get and __set in this manor http://gist.github.com/351387 (similar to the way that doctrine does it), then only ever accessing the properties via the $obj->var in an outside of the class. That way you can override functionality as needed instead of making a huge __get or __set function, or overriding __get and __set in the child classes.