__call magic creating new classes in PHP - php

I am using the __call magic within some of my mvc code to produce an autoloadable forms framework but I have ran into a problem I am hoping some one on here might have a work around for.
The __call magic takes two paramters: $methodName and $arguments. The arguments come back as an array of args which you called. Normally this function is called on methods you can do as such so feed these arguments into a function:
call_user_func_array($methodName, $arguments);
And this will propogate the methods signature with the arguments. I am trying to do something a little more complex. I am attempting to propogate a classes constructor the same way, through being able to send maybe a imploded comma deliminenated array of the arguments into the classes constructor or just sending the args in directly but both of these do not produce the required result. When I send an imploded array down into the constructor PHP thinks it's a string and when I send the array it thinks it's an array.
This is the code I am using atm:
public function __call($method, $args){
return $this->init_element(new $method($args['name'], $args['value'], $args['opts']));
}
What if I had 4 arguments to pass down though? Is there a way I can get it to dynamically fill the constructor just like you can for a function using call_user_func_array()?
I could use an attributes() function to do this but I would really like to be able to do it like I can with functions.
Thanks in advance,

Use PHP's reflection classes: (http://php.net/manual/en/class.reflectionclass.php)
$obj = new ReflectionClass( $classname );
then
$ins = $obj->newInstanceArgs( $arguments );
or
$ins = $obj->newInstance( );

I saw the following somewhere around the web:
call_user_func_array(array($obj, '__construct'), $args);

Related

Prophecy - Expect that no method will be called on an object

right now I'm using the following code in PHPUnit to expect that no method is called on a mock:
$object = $this->createMock(ClassA:class);
$object->expects($this->never())->method($this->anything());
So far I haven't found a way to achieve the same result in Prophecy. I only have been able to test assumptions on specific methods so far and not on all methods like in the sample above.
Currently I'm using the following custom assertion to test whether no method has been called. Prophecy's ObjectProphecy exposes a method to get all calls to a specific function so I'm using reflection to get all methods on a class and than each call for each method. If the array of calls is empty afterwards, I know that no method has been called. The method now looks like this:
public function assertNoMethodHasBeenCalled(ObjectProphecy $prophecy, string $className)
{
$methods = get_class_methods($className);
$calls = [];
foreach ($methods as $method) {
$reflectionMethod = new \ReflectionMethod($className, $method);
$numArgs = count($reflectionMethod->getParameters());
$calls = array_merge(
$calls,
$prophecy->findProphecyMethodCalls(
$method,
new ArgumentsWildcard(array_fill(0, $numArgs, Argument::any()))
)
);
}
$this->assertEmpty($calls);
}
It's working for my limited sample size so far but I'm not happy with it. I feel like there should be an easier way to achieve the same result.
To my knowledge, there is no simple to achieve this with Prophecy.
Prophecy works differently from PHPUnit's mocks when it comes to expectations. As soon as you set up an expectation, every call to your mock that isn't a prediction or a promise, will fail the test. Given the following object prophecy:
$prophecy = $this->prophesize(ClassA::class);
$prophecy->methodA()->shouldNotBeCalled();
$objectA = $prophecy->reveal();
Both
$objectA->methodA();
and
$objectA->methodB();
will fail the test.
So, when you don't set up any expectations, you have to check for calls manually like you did.

How to call a function from an array, which is in a class

My problem is this, i have a function which is stored in an array which is a part of a class. I want to call a function from this array using call_user_func() however i can't seem to figure out how to write this.
Calling a function from an array which is not in a class can be done like such.
$thearray = array( 0 => 'funcone', 1 => 'functwo');
call_user_func($thearray[0]);
However when i try to do this to an array which is in a class, it do sent work, i imagine because i need to reference the class somehow. I know that you can call a function from a class like this:
call_user_func(array($myclass, 'funcone'));
But my question is how would a call a function from an array, which is within a class, by using call_user_func(); i hope somebody can help me with this, i have a feeling that it is just a matter of how its written.
Assuming the array within the class is public, you can do:
call_user_func(array($myclass, $myclass->thearray[0]));
Did that answer your question?
Update:
I tried the following and it worked:
<?php
class Foo {
public function bar() {
echo "quux\n";
}
public $baz = array('bar');
}
$foo = new Foo();
call_user_func(array($foo, $foo->baz[0]));
shell$ php userfunc.php
quux
Try this?
call_user_func(array($this, $thearray[0]));
http://codepad.org/lCCUJYLK
Please bear with me as it's going to be a bit long. :)
Well, i think we can achieve this via PHP's overloading concept, which as most of you know is quite different from other object-oriented languages.
From the PHP manual's overloading page - Overloading in PHP provides means to dynamically "create" properties and methods. These dynamic entities are processed via magic methods one can establish in a class for various action types. (http://www.php.net/manual/en/language.oop5.overloading.php)
Much of this overloading magic is dependent of PHP's magic methods
If you see the list of magic methods, the one that can help us here is __call()
The magic method __call will be called every time a non-existing class method is called.
This will help us prevent throwing up any errors / set any custom messages. So, here is an example that we can use to solve the problem stated above.
<?php
class Test
{
private $arr = array( 'funcone', 'functwo' );
public function __call( $func_name, $func_args ) {
echo "Method called: " . $func_name . "\n";
echo "Arguments passed: " . $func_args . "\n";
// this will call the desired function.
call_user_func( array( $this, $this->arr[ $func_args ] ) );
}
}
$obj = new Test;
// run the first function in the array
$obj->runTest(0);
?>
Hope that helps. If this doesn't work, i'm sure it can be tweaked with a little trial and error. ( Now, i am talking PHP, right? tweaks... ;) )

Php Custom Mvc - how to check if function gets arguments?

Im working lately on a custom mvc for php, and one of the question was really bothered me:
Ive got the controller class, and i want to check if a certain function of the class getting arguments, and if not, return false.
is there any method to do it?
cause i searched in php.net and google and didn't find anything....
thanx!
Use reflection:
$reflection = new ReflectionMethod ($class_name, $method_name);
$params = $r->getParameters();
$params is now an array of ReflectionParameter objects
Have a look at func_get_args
You can use it inside the method in your controller to get the list of all arguments passed to the method.
You also have func_num_args that will just give you the number of arguments passed to your method.
Use function func_get_args
function sum(){
$s=0;
foreach(func_get_args() as $a) $s+= is_numeric($a)?$a:0;
return $s;
};
print sum(1,2,3,4,5,6); // 21

Php (eval vs call_user_func vs variable functions ...)

Even though there's some discussions regarding this issue I wanted to check on certain example what would be the best approach.
Instead of using existing solutions I created my own persistence layer (like many do)
So my approach is also in question here.
For every table in db I have model class that has appropriate getters and setters and some mandatory methods. I also created only one generic DAO class that handles all types of model objects.
So, for example to save any model object I instantiate genericDAO class and call save method that I pass model object as attribute.
Problem is that in runtime genericDAO class doesn't know whitch model object it gets and what methods (getters and setters) exist in it, so I need to call mandatory model class method that retrieves list of attributes as multiple string array.
For example for every attribute there's array(table_column_name,attribute_name,is_string).
When I call save function it looks like this:
public function save(&$VO) {
$paramArray = $VO->getParamArray();//get array of attributes
$paramIdArray = $paramArray[0]; //first attribute is always id
/*create and execute getId() and store value into $void to check if it's save or update*/
eval('$voId = $VO->get'.ucfirst($paramIdArray[1]).'();');
...
Currently I'm using eval to execute those methods, but as it is well known eval is very slow.
I'm thinking of changing that into call_user_func method
Something like:
$voId = call_user_func(array($VO, 'get'.ucfirst($paramIdArray[1])));
But also there's other solutions. I can maybe use something like this $method = 'get'.ucfirst($paramIdArray[1]));
$voId = $VO->$method();
or else
$method = 'get'.ucfirst($paramIdArray[1]));
$voId = $VO->{$method}();
What would be the best way?
First of all, there's no need to pass references like you are doing. You should give this a read to try to understand how PHP handles object references.
So public function save(&$VO) { should become public function save($VO) {.
Second, there is no need to use eval (in fact, it's better not to because of speed, debugability, etc). You can't stack-trace an eval call like you can a dynamic one.
Third, call_user_func is all but useless since PHP supports dynamic variable functions. Instead of call_user_func(array($obj, $method), $arg1), just call $obj->$foo($arg1). The call_user_func_array function is still useful since it supports variable length arguments and supports passing references.
So, ultimately, I would suggest this:
$method = 'get' . ucfirst($paramIdArray[1]);
$voId = $VO->$method();
Note that there's no need to call method_exists, since it may be callable and not exist due to __get magic method support...
I normally would use:
$method = 'get'.ucfirst($attribute);
if(method_exists($obj, $method){
$obj->$method();
}
But unless there is a very good reason i would just return a key => value array from getParamArray. And operate on that instead of using the getters...

Proper way to access an object

I am working with the Facebook PHP library. It creates an object called $facebook.
In order to access the object within my functions I have to pass the object along with other parameters I want the function to process.
Is there a better way or is passing the object to the function an appropriate practice?
In your function definition: global $facebook;.
Making the functions member functions of the facebook object. (though it won't be logicical for each and every function, it will make sense for quite some possible functions)
Funnily enough, the only thing that will actually change is that your object now becomes a "hidden" parameter instead of an actual one.
Passing the variable is fine - it at least keeps you from defining $facebook as a global.
You could write a class for your functions, and pass the object in the constructor, e.g/
$myFacebook = new MyFacebook($facebook);
class MyFacebook {
private $instance;
public function __construct($facebookInstance) {
$this->instance = $facebookInstance;
}
}

Categories