I have a variable like $string = "blah";
How can I create a function that has the variable value as name?
Is this possible in PHP?
Like function $string($args){ ... } or something, and be able to call it like:
blah($args);
this might not be a good idea, but you can do something like this:
$string = "blah";
$args = "args"
$string = 'function ' . $string . "({$args}) { ... }";
eval($string);
That doesn't sound like a great design choice, it might be worth rethinking it, but...
If you're using PHP 5.3 you could use an anonymous function.
<?php
$functionName = "doStuff";
$$functionName = function($args) {
// Do stuff
};
$args = array();
$doStuff($args);
?>
Okay, challenge accepted!
No matter how weird the question is (it's not btw), let's take it seriously for a moment! It could be useful to have a class that can declare functions and make them real:
<?php
customFunctions::add("hello", // prepare function "hello"
function($what) {
print "Hello $what, as Ritchie said";
print "<br>";
}
);
customFunctions::add("goodbye", // prepare function "goodbye"
function($what,$when) {
print "Goodbye cruel $what, ";
print "I'm leaving you $when";
print "<br>";
}
);
eval(customFunctions::make()); // inevitable - but it's safe!
That's it! Now they're real functions. No $-prefixing, no runtime evaluations whenever they get called - eval() was only needed once, for declaration. After that, they work like any function.
Let's try them:
hello('World'); // "Hello World"
goodbye('world','today'); // "Goodbye cruel world, I'm leaving you today"
Magic behind
Here's the class that can do this. Really not a complex one:
class customFunctions {
private static $store = [];
private static $maker = "";
private static $declaration = '
function %s() {
return call_user_func_array(
%s::get(__FUNCTION__),
func_get_args()
);
}
';
private static function safeName($name) {
// extra safety against bad function names
$name = preg_replace('/[^a-zA-Z0-9_]/',"",$name);
$name = substr($name,0,64);
return $name;
}
public static function add($name,$func) {
// prepares a new function for make()
$name = self::safeName($name);
self::$store[$name] = $func;
self::$maker.=sprintf(self::$declaration,$name,__CLASS__);
}
public static function get($name) {
// returns a stored callable
return self::$store[$name];
}
public static function make() {
// returns a string with all declarations
return self::$maker;
}
}
It provides an inner storage for your functions, and then declare "real" functions that call them. This is something similar to fardjad's solution, but with real code (not strings) and therefore a lot more convenient & readable.
Try call_user_func_array()
php.net link
You can call a function by its name stored in a variable, and you can also assign a function to variables and call it using the variable. If it's not what you want, please explain more.
Related
This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Use a variable to define a PHP function
Use Variable as Function Name in PHP
I want to perform a conditional function call but I don't necessarily know what what the function will be, so that would be a long switch.
For example;
$userSelection = "calculator"; /* or "stocks" or whatever widget */
$widget->get_widget($userSelection);
public function __construct($userSelection){
/* pseudo code */
call function $userSelection();
}
public function calculator(){
/* Get Calculator */
}
Sure there is. This feature is called variable functions:
$functionName = "strlen";
$length = $$functionName("Hello world!");
The $$var(...) syntax is convenient, but it will only work with free functions. If you want to call a class method this way, you will need to use call_user_func or call_user_func_array (these functions can also handle the "free function" case).
Look at the call-user-func function. This allows you to call another function, e.g.
call_user_func('calculator')
call_user_func($userSelection);
http://php.net/manual/en/function.call-user-func.php
Take a look at this php functions:
call_user_func(): http://php.net/manual/de/function.call-user-func.php
call_user_func_array(): http://www.php.net/manual/de/function.call-user-func-array.php
create_function(): http://www.php.net/manual/de/function.create-function.php
There is also a direct (though ugly) execution syntax:
function some_func(args) {...}
$function_name='some_func';
$$function_name(args2);
You can use call_user_func() for that, like this:
$userSelection = "calculator";
call_user_func($userSelection[, $param1, $param2, ...]);
call_user_func_array($userSelection, $params);
If it's just a function you're after then using this should solve your problems
$function = "echo";
$$function "fooBar";
If it's a class method that you want to keep flexible use magic method __call() which will allow you to use method names that are not pre-defined.
__call() is triggered when invoking inaccessible methods in an object context.
i.e.
class Foo {
public function __call($name, $arguments) {
echo $name;
}
}
$foo = new Foo();
$foo->bar(); // will echo "bar"
PHP built-in function 'eval' can do everything, but beware of injection.
$var = "somefunction";
eval("$var();");
http://php.net/manual/en/function.eval.php
It's pretty simple if that's what you mean.
function calculator() {
echo 'foo';
}
$userSelection = "calculator";
if (function_exists($userSelection)) {
$userSelection();
}
Or within a class like in your example:
class widget {
public function __construct($userSelection) {
echo 'constructed widget<br>';
if (function_exists($userSelection)) {
$this->$userSelection();
}
}
public function calculator() {
echo 'bar';
}
}
$userSelection = "calculator";
$widget = new widget($userSelection);
Or from outside a class when the function is part of the class.
class widget {
public function calculator() {
echo 'bar';
}
}
$widget = new widget();
$userSelection = "calculator";
$widget->$userSelection();
I would work with if/else statements though to determine the function to be called just to be sure that only valid functions are executed (do you sanitize the user selection or do you just get it from a $_POST? The latter would be a very bad idea).
You can do following :
$var = 'abc';
switch ($var) {
case 'abc':
$result = $var('test param');
echo $result;
break;
default :
echo 'default';
break;
}
function abc($data) {
return $data;
}
Can I do the following in PHP?
$lstrClassName = 'Class';
$lstrMethodName = 'function';
$laParameters = array('foo' => 1, 'bar' => 2);
$this->$lstrClassName->$lstrMethodName($laParameters);
The solution I'm using now, is by calling the function with eval() like so:
eval('$this->'.$lstrClassName.'->'.$lstrMethodName.'($laParameters);');
I'm curious if there is a beter way to solve this.
Thanks!
You don't need eval to do that ... depending on your version
Examples
class Test {
function hello() {
echo "Hello ";
}
function world() {
return new Foo ();
}
}
class Foo {
function world() {
echo " world" ;
return new Bar() ;
}
function baba() {
}
}
class Bar {
function world($name) {
echo $name;
}
}
$class = "Test";
$hello = "hello";
$world = "world";
$object = new $class ();
$object->$hello ();
$object->$world ()->$world ();
$object->$world ()->$world ()->$world(" baba ");
Output
Hello World baba
And if you are using PHP 5.4 you can just call it directly without having to declare variables
You might also want to look at call_user_func http://php.net/manual/en/function.call-user-func.php
Did you try your code? The best way to find out if something will work is by trying it. If you do try it, you will find that yes, it does work (assuming that $this has a property called Class which is an instance of an object that defines a method called function).
There are also the two functions call_user_func() and call_user_func_array()
I would suggest you call_user_func_array which can be used for functions and for arrays rather than eval.
However the syntax is different from what you suggested, and the fact that I tend to avoid eval while possible, you can use it with:
To call it with objects, just do it like:
$return=call_user_func_array(array($objInstance, "CLASSMETHOD"), $paramArray);
Untested but
this->$$lstrClassName->$$lstrMethodName($laParameters);
http://php.net/manual/en/language.variables.variable.php
I'm working on a project which requires a function to be copied & executed on the fly and variables in it needs to be replaced on the fly too.
A simple example will be like this:
function myfunction()
{
$abc = $_SESSION['abc'];
return $abc;
}
I want to be able to call myfunction1() which does NOT physically exist in the code but does exactly the samething as the one above except it now take values from my custom variable so it'll look like this:
function myfunction1()
{
$abc = $myCustomVariable;
return $abc;
}
Any one help pls?
The more you describe how convoluted your function is, the more it sounds like a perfect candidate for an object with injected dependencies.
For instance, you could have (just going to describe the basic interfaces here):
class myClass
{
public function __construct($provider DataProvider)
{
$this->provider = $provider;
}
// Please name this something better
public function doStufferer()
{
if ($this->provider->hasParam('foo'))
{
return $this->provider->getParam('foo');
}
}
}
class SessionProvider implements DataProvider
{
// Session specific stuff
}
class OtherProvider implements DataProvider
{
// Other provider stuff
}
interface DataProvider
{
public function getParam($key);
public function hasParam($key);
public function setParam($key, $value);
}
You can then use it like this:
$dataProcessor = new myClass(new SessionProvider);
// OR $dataProcessor = new myClass(new OtherProvider);
$dataProcessor->doStufferer();
Please take a look at PHP Classes and Objects and the other related topics.
This is what parameters are for, I think your looking todo something like this:
$myCustomVariable = 'Some value';
function myfunction($var=$_SESSION['abc'])
{
$abc = $var;
return $abc;
}
myfunction(); //returns $_SESSION['abc']
myfunction($myCustomVariable); //returns "Some Value"
The direct answer is eval which I do not recommend.
You could have your function accept a parameter, like this.
function myfunction1($some_var)
{
$abc = $some_var;
return $abc;
}
// call it like...
myfunction1($myCustomVariable);
If you need to access a variable, but the name is generated by dynamic code, you can use $GLOBALS.
function myfunction1($name_of_var)
{
$abc = $GLOBALS[$name_of_var];
return $abc;
}
// call it like...
$myCustomVariable = 'a value'
myfunction1('myCustom' + 'Variable');
I want to access private methods and variables from outside the classes in very rare specific cases.
I've seen that this is not be possible although introspection is used.
The specific case is the next one:
I would like to have something like this:
class Console
{
final public static function run() {
while (TRUE != FALSE) {
echo "\n> ";
$command = trim(fgets(STDIN));
switch ($command) {
case 'exit':
case 'q':
case 'quit':
echo "OK+\n";
return;
default:
ob_start();
eval($command);
$out = ob_get_contents();
ob_end_clean();
print("Command: $command");
print("Output:\n$out");
break;
}
}
}
}
This method should be able to be injected in the code like this:
Class Demo
{
private $a;
final public function myMethod()
{
// some code
Console::run();
// some other code
}
final public function myPublicMethod()
{
return "I can run through eval()";
}
private function myPrivateMethod()
{
return "I cannot run through eval()";
}
}
(this is just one simplification. the real one goes through a socket, and implement a bunch of more things...)
So...
If you instantiate the class Demo and you call $demo->myMethod(), you'll get a console: that console can access the first method writing a command like:
> $this->myPublicMethod();
But you cannot run successfully the second one:
> $this->myPrivateMethod();
Do any of you have any idea, or if there is any library for PHP that allows you to do this?
Thanks a lot!
Just make the method public. But if you want to get tricky you can try this (PHP 5.3):
class LockedGate
{
private function open()
{
return 'how did you get in here?!!';
}
}
$object = new LockedGate();
$reflector = new ReflectionObject($object);
$method = $reflector->getMethod('open');
$method->setAccessible(true);
echo $method->invoke($object);
EDIT:
Updated to include examples of private function calls with parameters.
As of PHP 5.4, you can use the predefined Closure class to bind a method/property of a class to a delta functions that has access even to private members.
The Closure class
For example we have a class with a private variable and we want to access it outside the class:
class Foo {
private $bar = "Foo::Bar";
private function add_ab($a, $b) {
return $a + $b;
}
}
PHP 5.4+
$foo = new Foo;
// Single variable example
$getFooBarCallback = function() {
return $this->bar;
};
$getFooBar = $getFooBarCallback->bindTo($foo, 'Foo');
echo $getFooBar(); // Prints Foo::Bar
// Function call with parameters example
$getFooAddABCallback = function() {
// As of PHP 5.6 we can use $this->fn(...func_get_args()) instead of call_user_func_array
return call_user_func_array(array($this, 'add_ab'), func_get_args());
};
$getFooAddAB = $getFooAddABCallback->bindTo($foo, 'Foo');
echo $getFooAddAB(33, 6); // Prints 39
As of PHP 7, you can use the new Closure::call method, to bind any method/property of an obect to a callback function, even for private members:
PHP 7+
$foo = new Foo;
// Single variable example
$getFooBar = function() {
return $this->bar;
};
echo $getFooBar->call($foo); // Prints Foo::Bar
// Function call with parameters example
$getFooAddAB = function() {
return $this->add_ab(...func_get_args());
};
echo $getFooAddAB->call($foo, 33, 6); // Prints 39
The first question you should ask is, if you need to access it from outside the class, why did you declare it private? If it's not your code, the originator probably had a good reason to declare it private, and accessing it directly is a very bad (and largely unmaintainable) practice.
EDIT: As Adam V. points out in the comments, you need to make the private method accessible before invoking it. Code sample updated to include this. I haven't tested it, though - just adding here to keep the answer updated.
That having been said, you can use Reflection to accomplish this. Instantiate ReflectionClass, call getMethod for the method you want to invoke, and then call invoke on the returned ReflectionMethod.
A code sample (though I haven't tested it, so there may be errors) might look like
$demo = new Demo();
$reflection_class = new ReflectionClass("Demo");
$reflection_method = $reflection_class->getMethod("myPrivateMethod");
$reflection_method->setAccessible(true);
$result = $reflection_method->invoke($demo, NULL);
Here's a variation of the other answers that can be used to make such calls one line:
public function callPrivateMethod($object, $methodName)
{
$reflectionClass = new \ReflectionClass($object);
$reflectionMethod = $reflectionClass->getMethod($methodName);
$reflectionMethod->setAccessible(true);
$params = array_slice(func_get_args(), 2); //get all the parameters after $methodName
return $reflectionMethod->invokeArgs($object, $params);
}
I have these problems too sometimes, however I get around it through my coding standards. Private or protected functions are denoted with a prefix underscore ie
private function _myPrivateMethod()
Then i simply make the function public.
public function _myPrivateMethod()
So although the function is public the naming convention gives the notification that whilst public is is private and shouldn't really be used.
If you are able to added a method in the class where the method is defined, you can add method which uses the call_user_method() internally. This works also with PHP 5.2.x
<?php
class SomeClass {
public function callprivate($methodName) {
call_user_method(array($this, $methodName));
}
private function somePrivateMethod() {
echo 'test';
}
}
$object = new SomeClass();
$object->callprivate('somePrivateMethod');
Answer is put public to the method. Whatever trick you are going to do it wouldn't be understandable to fellow developers. For example they do not know that at some other code this function has been accessed as public by looking at the Demo class.
One more thing. that console can access the first method writing a command like:. How can this even be possible? Console can not access demo class functions by using $this.
I guess the reflectionClass is the only alternative if you really want to execute some private methods. Anyhow, if you just need read access to privat or protected properties, you could use this code:
<?php
class Demo
{
private $foo = "bar";
}
$demo = new Demo();
// Will return an object with public, private and protected properties in public scope.
$properties = json_decode(preg_replace('/\\\\u([0-9a-f]{4})|'.get_class($demo).'/i', '', json_encode((array) $demo)));
?>
<?php
$request="email";
$data=[1,2,3,4,5];
$name=new Update($request,$data);
class Update{
private $request;
private $data;
function __construct($request,$data){
$this->request=$request;
$this->data=$data;
if($this->request=='email'){
$this->update_email();
}
else{
echo "Can't do anything";
}
}
private function update_email(){
echo $this->request;
echo '\n';
foreach($this->data as $x){
echo $x."\n";
}
}
}
?>
PHP
mysql database
I have created a follow on question to this one here that is specifically about pagination
I need to call a method from one class in another, and be able to change the method that is called. Like so
class db{
function a(){ echo 'I run a query';}
function b(){ echo 'im the other query';}
}
class YourClass {
var $fcn;
$db = new db()
function invoke(){
call_user_func($this->fcn);
}
}
$instance = new YourClass;
$instance->fcn = 'db->a';
$instance->invoke();
I want to use a method 'a' from the db class in the 'yourClass' method 'invoke'
Thanks
Ok this is what i have put together from the answers provided and it works.
class A {
function a(){
$x = 'Method a is used';
return $x;
}
function b(){
$x = 'Method b is used';
return $x;
}
}
class B {
function invoke($obj, $method){
echo call_user_func( array( $obj, $method) );
}
}
$instance = new B();
$instance->invoke(new A(),"a");
Which writes, 'Method a is used' to the screen
But i really want to be able to pass arguments to method "a" so i tried the code below.
class A {
function a($var1,$var2,$var3){
$x = 'the three passed values are ' . $var1 . ' and ' . $var2 . ' and ' . $var3;
return $x;
}
function b(){
$x = 'im method b';
return $x;
}
}
class B {
function invoke($obj,$arguments){
echo call_user_func_array($obj,$arguments);
}
}
$arguments = array('apple','banana','pineapple');
$use_function = array(new A(),"a");
$instance = new B();
$instance->invoke($use_function,$arguments);
It almost works but i get these errors above the correct answer
Missing argument 1 for A::a(),.....for argument 2 and 3 as well but then the answer prints to the screen
"the three passed values are apple and banana and pineapple"
I'm probably making a rookie mistake I've been coding all day. If someone could fix the script above and submit the working code, I would be eternally grateful. I have to put this issue to bed so i can go to bed.
Thanks
As of PHP5.3 you could use closures or functors to pass methods around. Prior to that, you could write an anonymous function with create_function(), but that is rather awkward.
Basically, what you are trying to do could be done with the Strategy Pattern.
removed example code, as it wasn't helpful anymore after the OP changed the question (see wiki)
Apart from that, you might want to look into Fowlers's Data Source Architectural Patterns. The Zend Framework (and pretty much all other PHP frameworks) offers database access classes you could use for these patterns and there is also a paginator class, so why not check them out to learn how they did it.
removed EDIT 1 as it wasn't helpful anymore after the OP changed the question (see wiki)
EDIT 2
Ok, let's take a step by step approach to this (not using a Strategy Pattern though)
What you are asking for in the question can easily be solved with this code:
class Foo
{
public function bar()
{
echo 'bar method in Foo';
}
}
class MyInvoker
{
protected $myObject;
public function __construct()
{
$this->myObject = new Foo();
}
public function __call($method, $args)
{
$invocation = array($this->myObject, $method);
return call_user_func_array($invocation, $args);
}
}
With this code you'd just call the appropriate methods. No setting of methods names. No clumsy extra invoke method. No reinventing of how methods are called. You dont need it, because PHP has the __call function that you just taught to send all methods not existing in MyInvoker to $myObject, e.g. Foo.:
$invoker = new MyInvoker;
$invoker->bar(); // outputs 'bar method in Foo called'
You might just as well have extended MyInvoker to be a subclass of Foo, e.g.
class MyInvoker extends Foo {}
and then you could do the same. This not what you need though and it illustrates how pointless it is, to do such a thing. MyInvoker now does nothing by itself. It is an empty class and effectively the same as Foo. Even with the previous approach using the __call method it is not doing anything. This is why I have asked you to be more specific about the desired outcome, which is a Paginator.
First try:
class Paginator()
{
// A class holding all possible queries of our application
protected $queries;
// A class providing access to the database, like PDO_MySql
protected $dbConn;
public function __construct()
{
$this->db = new MyPdo();
$this->queries = new DbQueries();
}
public function __call($method, $args)
{
$invocation = array($this->queries, $method);
$query = call_user_func_array($invocation, $args);
return $this->dbConn->query($query);
}
}
With that code, our Paginator creates everything it needs inside itself, tightly coupling the db connection class and all queries and it allows you to call upon these, like so
$paginator = new Paginator;
// assuming we have something like getImageCount() in DbQueries
echo $paginator->getImageCount();
What is happening then is, Paginator will recognize it doesnt know getImageCount() and will invoke the __call method. The __call method will try to invoke the getImageCount() method on the DbQueries. Since it exists, it will return the query, which in turn is passed to the db connection to execute it. Great you'd say, but it's not. In fact, this is horrible. Your paginator's responsibility is to count items in a table and fetch items from this table in a certain range and amount. But right now, it is not doing anything like this. It is completely oblivious to whats going on, so lets try a new class:
class Paginator
{
protected $dbConn;
protected $itemCount;
public function __construct($dbConn)
{
$this->dbConn = $dbConn;
}
public function countItems($query)
{
$this->itemCount = $this->dbConn->query('select count(*) from (?)', $query);
return $this->itemCount;
}
public function fetchItems($query, $offset = 0, $limit = 20)
{
$sql = sprintf('select * from (?) LIMIT %d, %d', $offset, $limit);
return $this->dbConn->query($sql, $query);
}
}
Much better. Now our Paginator is an aggregate instead of a composite, meaning it does not instantiate objects inside itself, but requires them to be passed to it in the constructor. This is called dependency injection (and also provides a loose coupling, when dbConn uses an interface) which will make your app much more maintainable, as it is easy to exchange components now. This will also come in handy when Unit Testing your code.
In addition, your Paginator now concentrates on what it is supposed to do: counting and fetching items of an arbitrary query. No need to pass methods around. No need for obscure method invocation. You'd use it like this:
$paginator = new Paginator($dbConn);
$query = $dbQueries->findImagesUploadedLastWeek(); // returns SQL query string
$images = $paginator->countItems($query);
if($images > 0) {
$images = $paginator->fetchItems($query);
}
And that's it. Well, almost. You'd have to render the pagination of course. But this should be rather trivial, if you extend what you already have above. The $imageCount property is a hint at where to go next.
Anyway, hope that I could shed some light.
P.S. The $this->dbConn->query($sql, $query) calls are of course dummy code. Dont expect to be able to copy and paste it and get it working. In addition, you should make sure the queries added to the Paginator SQL is safe to use. You wouldnt want someone to insert a query that deletes all your db rows. Never trust user input.
P.P.S. $query should be an SQL query string. Check the PHP manual for PDO::prepare. In general, it yields better performance and security to prepare a statement before executing it. The page in the manual will give you the clues about the ? in the query calls. If you dont want to use PDO, just use sprintf() or str_replace() to replace ? with $query, e.g. $this->dbConn->query(sprintf('SELECT count(*) from (%s)', $query) but keep in mind that this has none of the benefits of a prepared statement and potentially opens the door for SQL Injection vulnerabilities.
P.P.P.S Yes, Dependency Injection is generally a preferred strategy. This is an advanved topic though and might be too much to fully grasp right now, but it's well worth looking into it. For now, it should be enough if you try to favor favor aggregation over composition. Your classes should only do what they are responsible for and get any dependencies through the constructor.
Here are two ways of doing it:
class YourClass {
var $fcn;
function invoke($arguments){
//one way:
$this->{$this->fcn}($arguments);
//another way:
call_user_func_array(array($this, $this->fcn), $arguments);
}
function a(){
echo 'I am a()';
}
}
$instance = new YourClass;
$instance->fcn = 'a';
$instance->invoke();
This'll print out "I am a()" from inside the class.
you are almost there
class db {
function a(){ echo 'I run a query';}
function b(){ echo 'im the other query';}
}
class YourClass {
var $fcn;
function __construct() {
$this->db = new db();
}
function invoke() {
call_user_func(array(
$this->{$this->fcn[0]},
$this->fcn[1]
));
}
}
$instance = new YourClass;
$instance->fcn = array('db', 'a');
$instance->invoke();
$instance->fcn = array('db', 'b');
$instance->invoke();
the syntax is quite fancy, but it works
// edit: from your comment it looks like the simplest option is to pass method name as string, like this
class Paginator {
function __consturct($db, $counter_func) ...
function get_count() {
$args = func_get_args();
return call_user_func_array(
array($this->db, $this->counter_func),
$args);
}
}
new Paginator($db, 'get_num_products');
I am guessing that you are using php here. Php supports variable functions which might solve you problem but as far as I am aware does not support delegates/function pointers.
What database are you using? I would be against putting queries within the code and using stored procedures as an alternative, if this is supported in the database you are using. This may solve the underlying problem you have.
Are you asking if PHP has functional references? It doesn't. But it does let you call functions by putting their name in a string, or an array of a class name and method name.
See call_user_func() for a description, and variable functions.
class DB {
function a(){ echo 'I run a query';}
function b(){ echo 'im the other query';}
}
class B {
protected $db;
private $method;
function __constructor($db) { $this->db; }
function invoke($m){
$this->method = $m;
// Non static call
call_user_func( array( $this->db, $this->method ) );
}
}
$db = new DB();
$b = new B($db);
$b->invoke('a');
I have made little modifications to my initial answer. You could also check out this post, it may help:
Database and OOP Practices in PHP
The Observer Design Pattern may be useful for this sort of thing, or it might be a misuse of the pattern; I don't know yet. Anyway, for your consideration:
class DbObserver implements SplObserver
{
public function update(SplSubject $subject) // Required
{
$method = $subject->getObserverMethod();
$args = $subject->getObserverArgs();
$this->$method($args);
}
private function a($args)
{
echo 'I run query ' . $args[0] . '<br />';
}
private function b($args)
{
echo 'I run query ' . $args[0] . ' because ' . $args[1] . '<br />';
}
private function c()
{
echo 'I have no argument' . '<br />';
}
}
class ObserverObserver implements SplObserver
{
public function update(SplSubject $subject) // Required
{
if (count($subject->getAttached()) > 1) {
echo 'I saw that<br />';
} else {
echo 'Nothing happened<br />';
}
}
}
class DbSubject implements SplSubject
{
private $observerMethod;
private $observerArgs = array();
private $attached = array();
public function notify() // Required
{
foreach ($this->attached as $each) {
$each->update($this);
}
}
public function attach(SplObserver $observer) // Required
{
$this->attached[] = $observer;
}
public function detach(SplObserver $observer) // Required
{
$key = array_keys($this->attached, $observer);
unset($this->attached[$key[0]]);
}
public function setObserverMethod($method, $args = array())
{
$this->observerMethod = $method;
$this->observerArgs = $args;
return $this;
}
public function getObserverMethod()
{
return $this->observerMethod;
}
public function getObserverArgs()
{
return $this->observerArgs;
}
public function getAttached()
{
return $this->attached;
}
}
$db_subj = new DbSubject;
$db_obs = new DbObserver;
$db_subj->attach($db_obs);
$args = array('A');
$db_subj->setObserverMethod('a', $args)->notify();
$args = array('B', 'I can');
$db_subj->setObserverMethod('b', $args)->notify();
$obsvr = new ObserverObserver;
$db_subj->attach($obsvr);
$db_subj->setObserverMethod('c')->notify();
$db_subj->detach($db_obs);
$db_subj->notify();
/**
I run query A
I run query B because I can
I have no argument
I saw that
Nothing happened
**/
You need to make this change:
$arguments = array('apple','banana','pineapple');
$a = new A();
$use_function = array(&$a,"a"); // Make this changes to your code
$instance = new B();
$instance->invoke($use_function,$arguments);
class A {
function a(){ echo 'I run a query';}
function b(){ echo 'im the other query';}
}
class B {
function Test() {
invoke(new $A(), "a");
}
function invoke($obj, $method){
// Non static call
call_user_func( array( $obj, $method ) );
// Static call
//call_user_func( array( 'ClassName', 'method' ) );
}
}
I hope this helps.