In a PHP routing file, I want to make a callback to a function called homepage_display().
The function name is in the $callback variable, and when I make the call, it doesn't work:
$callback = "homepage_display";
$callback(); // doesn't work
call_user_func($callback); // doesn't work either
homepage_display(); // works!!
Whereas this specific piece of code just above works in any snippet, the same mechanism doesn't work in one of my functions. Any idea of what can cause such a behavior? I tried removing the _ thinking it might be an encoding problem, but it doesn't solve anything.
EDIT:
To make my point absolutely clear, I added an explicit assignation $callback="homepage_display";, just before calling it as a callback function. You can see on this picture that it just does not work. Whereas calling homepage_display(); directly, does. If somebody understands something, I'm curious :)
Not working:
Working:
The answer, in one word: namespace foo\bar;.
One cannot call $callback(); when in the scope of a non-global namespace.
One has to call call_user_func(__NAMESPACE__.'\\'.$callback); instead.
It can get tricky sometimes ;)
Works fine here:
php > function foo() { echo 'foo!'; }
php > $bar = 'foo';
php > call_user_func($bar);
foo!
php > $bar();
foo!
Did you verify that your testRoute() actually returns true? If it doesn't, then your "autoloader" will never get called.
Related
I have some code that has been working for a long time, but is now producing perplexing errors. I have to assume this was caused by my moving to php 7.3, but I can't find any references that explain what is happening.
I have a method in a class that looks something like:
class Foo {
function bar($param = OtherClass::MY_CONSTANT) {
logger(__METHOD__);
logger(OtherClass::MY_CONSTANT);
logger($param);
logger('ready to do stuff');
// does stuff
}
}
Where OtherClass::MY_CONSTANT = 1.
When I call that method from another class:
$foo = new Foo();
$foo->bar();
the output is something like:
DEBUG - Foo::bar
DEBUG - 1
and then php execution stops abruptly, not even calling my registered shutdown function. I am able to use the class constant directly in the body of the method, but I am not able to use the parameter set to the class constant's value by default.
If I change the method to
function bar($param = 1) {
everything works fine.
Also, if I pass the constant when I call the method it works:
$foo = new Foo();
$foo->bar(OtherClass::MY_CONSTANT);
I get the happy
DEBUG - Foo::bar
DEBUG - 1
DEBUG - 1
DEBUG - ready to do stuff
and execution continues normally.
Something about using a class constant as a default is making the variable poisonous, even though I can use the class constant in the method without any trouble.
I tried to create a simple one-file example to recreate this problem, but it worked just fine. Aargh.
Has something changed in php 7.3 that would cause this behavior? I just upgraded to 7.3.1 but the problem persisted. Is there a better practice I should be using?
EDIT TO ADD:
After a few hours trying to make a simple case to reproduce this, I have to move on. Relevant factors include:
running in php-fpm
code running after closing the connection to the browser.
even constants in the same class (self::MY_CONSTANT) create poison variables
My solution was to roll back to php 7.2.14, which is working properly. I can only assume this in a bug in php 7.3.
As a workaround, you can do it like this:
function bar($param = null) {
if ($param === null) {
$param = OtherClass::MY_CONSTANT;
}
logger(__METHOD__);
logger(OtherClass::MY_CONSTANT);
logger($param);
logger('ready to do stuff');
// does stuff
}
This assumes that null is not a valid value for the parameter; replace that with some other invalid value if it is. If the parameter can legitimately be anything, this workaround won't work.
I'm just a once-in-a-while PHP developer. Now, working on a legacy application, I just hit upon the following problem, which seems very stupid. But I can't get $someString class variable to hold the right value:
class MyClass{
var $someString;
function doSomething(){
//$this->setString(); //this is effectively not called here, but later in getIframe()
$this->buildIframe();
echo $this->someString; //actually, I need someString here, but it is empty
}
function setString(){
$this->someString = "something";
}
function buildIframe(){
$content .= <iframe....>;
}
function getIframe(){
$this->setString();
}
}
$myClassInstance = new MyClass();
$myClassInstance->doSomething();
$myClassInstance->getIframe();
As far as I can see, doSomething() is called in a class context, as I did show.
What am I doing wrong?
EDIT:
I reviewed the code and I think I found whats causing this. There is an iframe embedded into the html output, which is generated at one part and called later on. So the setString() method is actually not called imediately, what I thought first but when invoking the iframe code. So thats why it's not available where I need the string output.
I guess like the code is now, there is no way to get the $someString output except inside the getIframe() method.
This code is 100% correct and working. I've checked it on PHP 5. It echos "something" in string. And it is proper behavior.
From manual:
Note: The PHP 4 method of declaring a variable with the var keyword is still supported for compatibility reasons (as a synonym for the public keyword). In PHP 5 before 5.1.3, its usage would generate an E_STRICT warning.
I am interested in something google couldn't really help me with...
I know that its possible to use anonymous functions and also store functions in a variable in PHP like that
$function = function myFoo() { echo "bar"; }
and call it using the variable: $function();
So far so good but what if I have a function or method declared somewhere but not saved on intializing?
I have a function that shall expect a callable, of course call_user_func() can help me here but then I need to pass the method name in my callback handler which I think is pretty unsafe because in the moment I add the callback I cant say if it really is a function and exists when I store it.
Thatswhy I would like to realize the following szenario:
This function:
function anyFunction() {
echo "doWhatever...!";
}
should be saved in a variable at a later point in time:
$myOtherFunction = get_registered_func("anyFunction");
I know get_registered_func() doesnt exist but I want to know if this is possible somehow!
With this I could now have another function
function setCallback(callable $theCallbackFunction) { }
And use it like this:
setCallback($myOtherFunction);
This would have a great advantage that an exception / a fatal is thrown when the parameter is no function or does not exist.
So in short, is there a way to store a previously defined, already existing function or method in a variable?
PHP's callable meta type can be:
a string
an array
an anonymous function
Only the latter one is somewhat "type safe", i.e. if you get an anonymous function you know it's something you can call. The other two options are merely formalised informal standards (if that makes sense) which are supported by a few functions that accept callbacks; they're not actually a type in PHP's type system. Therefore there's basically no guarantee you can make about them.
You can only work around this by checking whether the callable you got is, well, callable using is_callable before you execute them. You could wrap this into your own class, for example, to actually create a real callable type.
I see no reason why this shouldn't be possible, other than there not being a PHP function to do it. The anonymous function syntax is newly introduced in PHP, I wouldn'be surprised if it was still a little rough around the edges.
You can always wrap it:
function wrap_function ($callback) {
if (is_callable($callback) === false) {
throw new Exception("nope");
}
return function () {
call_user_func($callback, func_get_args());
}
}
$foo = new Foo();
$ref = wrap_function(array($foo, "bar"));
Not a good way, but maybe this helps you:
function foo($a) {
echo $a;
}
$callFoo = 'foo';
$callFoo('Hello World!'); // prints Hello
EDIT: Sorry guys, it was a typo =(
I feel embarrassed for wasting your time on this. I'm leaving this thread open in hopes that someone might find the discussed information useful.
To clarify further, the code below will work as expected, I mistyped 'classHandler' in my code, and that's the reason PHP couldn't find it.
Also, the syntax errors noted by some commenters have been corrected
I feel obligated to summarize the discussion on this thread:
#wimvds suggests using inheritance and that my implementation is not a good practice.
#Victor Nicollet disagrees saying extending the behavior of an existing instance is 1. impossible and 2. bad design
#ircmaxell adds: Remember, you should always favor composition over inheritance. And this isn't spaghetti code, it's a pretty standard method of implementing a stripped down notification system (You could build a full blown observer or mediator pattern, but for really simple tasks, this may be a whole lot better since it's easier to maintain).
#Victor asks for a minimal one file example returning this error. This is what helped me solve the issue. When I tried the sample file, it work perfectly leading me to believe that something else indeed was wrong.
#Shakti Singh suggests trying call_user_func( array( $this, $this->handler ), $var);
#Victor Nicollet responds saying This would attempt to call a member function $this->classHandler (which probably doesn't exist) instead of the global classHandler
#abesto gives it a shot, ends up with a very similar implementation as my own, which works without my typo.
#Victor Nicollet answers by claiming that the classHandler needs to be defined prior to the call.
#Blizz responds by saying that PHP parses classes and functions first and then the regular code.
MyClass.php ( singleton )
public $handler;
public function myMethod()
{
$var = "test";
call_user_func( $this->handler, $var );
// PHP Warning: First argument is expected to be a valid callback
}
Script.php
$myClass = new MyClass;
$myClass->handler = "classHandler";
$myClass->myMethod();
function classHandler( $var )
{
echo $var;
}
If this is incorrect, what is the commonly practiced means of invoking handlers / event handlers in php?
Note that this is a simplified version of the actual script
You have to call something like this
call_user_func( array( $this, $this->handler ), $var);
Read your Script.php code again. What it's doing is:
Instantiate MyClass (I'm assuming you forgot the new here).
Define the handler to be classHandler.
Run myMethod(), which attempts to call classHandler.
Define classHandler.
Obviously, if you run 3 before you run 4, it's not going to work. You must define the function first, and then run any code that might want to call it.
In the larger scheme of things, I suspect there is no file like Script.php, and instead file A defines the class, file B instantiates the class and runs myMethodand file C defines classHandler. In such a situation, you need to make sure that file C is loaded before B is run.
First of all: if by storing functions as strings you mean that the actual implementation is in the string, then this is bad practice. You don't have to do it to get what you want.
function afun($param) {}
class BClass { function bfun($param) {} }
call_user_func('afun', 'param'); // Calls function afun
$binstance = new BClass();
call_user_func(array($binstance, 'bfun'), 'param'); // Calls bfun on binstance
// Update according to comment
class CClass {
private $handler;
public function __construct($handler) { $this->handler = $handler; }
public foo() {
// do stuff
call_user_func($this->handler, 'param');
}
}
$cinstance = new CClass('afun');
$cinstance->foo();
Is there any reason why I can't use preg_replace inside a static function? when I move the code out of it, it works perfectly. Any ideas?
Funny, because this works fine:
class obnoxiousWeasel {
public static function callMeDoItIDareYa($omgudid)
{
return preg_replace("/(, you don\'t listen)/", '...', $omgudid);
}
}
$pieceofmymind = "ok, but what's the point, you don't listen";
$reply = obnoxiousWeasel::callMeDoItIDareYa($pieceofmymind);
echo $reply;
returns: "ok, but what's the point..."
We will need to see your code before we can tell you what is wrong. Using preg_replace inside a static function is definitely not the problem.
Edit: I actually edited the above useless function to improve it. Might as well face it, I'm addicted to refactoring.
preg_replace is a core php function and can be used at any scope.
perhaps you are using it to evaluate a class member in the static method? that would not work. but I couldn't say for sure without seeing a relevant chunk of code.