I'm working my way through php callbacks. I think I've covered the basics, but when working within class extensions I'm still hitting a brick wall somewhere for some time now, therefore it is time for some stack overflow rubber duck programming...!
Calling a callback from a class extension:
class myClass {
function cb_check($function) {
call_user_func($this->$function);
}
static function myFunction() {
var_dump("Hello World");
}
}
class myExtClass extends myClass {
function cb_invoke() {
$this->cb_check('myFunction');
}
}
$x = new myExtClass;
$x->cb_invoke();
Error message (or, notice and warning):
Notice: Undefined property: myExtClass::$myFunction in F:\test.php on
line 5
Warning: call_user_func() expects parameter 1 to be a valid callback,
no array or string given in F:\test.php on line 5
Line 5 is the call_user_func() above.
Does anybody have an idea what I am missing here?
Thank you in advance!
As mark pointed out,
call_user_func($this->$function);
should be replaced by either
call_user_func(array($this, $function));
or
call_user_func('self::' . $function);
Thanks, Mark!
While working with static classes you should have to use scope resolution operator :: you can not create the instance directly .
$x::myExtClass;
Try it.
Your error arises because you've declared myFunction() to be static. Static methods don't belong to any specific instance of a class and therefore can't be accessed through the $this variable. Instead you use self::myFunction() to call the static method. The easiest way to make this happen is to build the string of the static method call and pass the string as the parameter to call_user_func(). Your code would work as-written if myFunction() were not static.
class myClass {
function cb_check($function) {
// Build a static-method-style string
call_user_func('self::' . $function);
}
static function myFunction() {
var_dump("Hello World");
}
}
class myExtClass extends myClass {
function cb_invoke() {
$this->cb_check('myFunction');
}
}
$x = new myExtClass;
$x->cb_invoke();
Related
Here is my Class:
class ProcessUploadedExcel {
public static function test1($a,$b)
{
dd('hi');
}
public static function test2($a,$b)
{
dd('hi');
}
}
in another file I want to call one of the functions. So I included the file:
use App\Library\ProcessUploadedExcel;
the function is stored in a variable and when I use call_user_func_array I get an error:
ProcessUploadedExcel::test1(1,2);//works fine.
$func_name = 'test1';
call_user_func_array("ProcessUploadedExcel::" . $func_name, [1,2]);//gets error
error:
call_user_func_array() expects parameter 1 to be a valid callback,
class 'ProcessUploadedExcel' not found
You can do this:
class ProcessUploadedExcel {
public static function test1($a,$b)
{
//dd('hi');
var_dump($a,$b);
}
public static function test2($a,$b)
{
dd('hi');
}
}
$func_name = 'test1';
ProcessUploadedExcel::$func_name(1,2);
Output:
int(1) int(2)
or if you want to use call_user_func_array()
call_user_func_array([ProcessUploadedExcel::class,$func_name],[1,2]);
Both solutions work properly with use and namespaces.
call_user_func_array ignores the use and you have to provide the full path:
$func_name = 'test1';
call_user_func_array("App\Library\ProcessUploadedExcel::" . $func_name, [1,2]);
You can try this way:
class ProcessUploadedExcel {
public static function test1($a,$b)
{
echo ('hi');
}
public static function test2($a,$b)
{
echo ('hi');
}
}
$func_name = 'test1';
call_user_func_array([ ProcessUploadedExcel::class, $func_name ] , [1,2]);
First misconception is that you "included the file: use App\Library\ProcessUploadedExcel;". No, you just told PHP that whenever it encounters ProcessUploadedExcel, you actually mean App\Library\ProcessUploadedExcel. This doesn't include anything. Including something is a different mechanism using require or require_once. Actually including the file is done by the autoloader in most projects.
Now, you pass a string to call_user_func_array(). PHP doesn't look inside that string, so it can't tell that you mean something different than what you write there. Inside the called function, where the string is used, the above use ... is not effective, so the function fails since it can't find the according callback.
Remedies:
You could provide the fully qualified name "App\\Library\\ProcessUploadedExcel::test1" as parameter.
You could make PHP look up the fully qualified name for you using ProcessUploadedExcel::class . "::test1".
I'm not sure that either of these works though, but check the documentation which way to specify a callback exist. Maybe you need to specify class and function separately like [ProcessUploadedExcel::class, "test1"].
I'm not so sure what the following object instantiation is called but it comes from a article that i'm reading.
class foo
{
function out()
{
return 'hello';
}
}
echo (new foo())->out();
The object is instantiated automatically and calls the out method. But what i dont really understand is when i rename the out() method into a fictitious method i get an error like this:
example:
class foo
{
function out()
{
return 'hello';
}
}
echo (new foo())->ou();
Fatal error: Call to undefined method foo::ou() in ...
Is this method somehow being called as a static method?
The :: does not stand for static method, this is a missconception. The :: is a "scope resolution operator", it denotes the identification of a method by its class predicated full name.
So this simply means: "method 'ou' as defined by class 'foo'". Not more, not less.
No. The error just indicates that the method doesn't exist. It always shows the :: for this error, no matter whether you call the method in a static way or not. You would get the same error if you changed the code to:
$foo = new foo();
echo $foo->ou();
Second code example as per request in comments:
$moo = new moo(); // Parentheses optional, I guess
$foo = new foo($moo);
$foo->out();
Does php support method overloading. While trying below code it suggests it supports method overloading. Any views
class test
{
public test($data1)
{
echo $data1;
}
}
class test1 extends test
{
public test($data1,$data2)
{
echo $data1.' '.$data2;
}
}
$obj = new test1();
$obj->test('hello','world');
As i have overload the method it gives the output as "hello world".
Above code snippet suggests php supports method overloading. So my question is does php support method overloading.
You should make the difference between method overriding (your example) and method overloading
Here is a simple example how to implement method overloading in PHP using __call magic method:
class test{
public function __call($name, $arguments)
{
if ($name === 'test'){
if(count($arguments) === 1 ){
return $this->test1($arguments[0]);
}
if(count($arguments) === 2){
return $this->test2($arguments[0], $arguments[1]);
}
}
}
private function test1($data1)
{
echo $data1;
}
private function test2($data1,$data2)
{
echo $data1.' '.$data2;
}
}
$test = new test();
$test->test('one argument'); //echoes "one argument"
$test->test('two','arguments'); //echoes "two arguments"
So my question is does php support method overloading(?).
Yes, but not in that way, and, in your example, it not suggests that this kind of overloading is correct, at least with the version 5.5.3 of it and error_reporting(E_ALL).
In that version, when you try to run this code, it gives you the following messages:
Strict Standards: Declaration of test1::test() should be compatible
with test::test($data1) in /opt/lampp/htdocs/teste/index.php on line 16
Warning: Missing argument 1 for test::test(), called in /opt/lampp/htdocs/teste/index.php
on line 18 and defined in /opt/lampp/htdocs/teste/index.php on line 4
Notice: Undefined variable: data1 in /opt/lampp/htdocs/teste/index.php on line 6
hello world //it works, but the messages above suggests that it's wrong.
You forgot to add 'function' before test in both cases. Method is called of child class because when you call a method from child class object it first check if that method exist in child class, if not then it look into inherited parent class with visibility public or protected check and if method is exist than return the result according to that.
This question already has answers here:
Reference - What does this error mean in PHP?
(38 answers)
Closed 8 years ago.
So I'm refactoring my code to implement more OOP. I set up a class to hold page attributes.
class PageAtrributes
{
private $db_connection;
private $page_title;
public function __construct($db_connection)
{
$this->db_connection = $db_connection;
$this->page_title = '';
}
public function get_page_title()
{
return $this->page_title;
}
public function set_page_title($page_title)
{
$this->page_title = $page_title;
}
}
Later on I call the set_page_title() function like so
function page_properties($objPortal) {
$objPage->set_page_title($myrow['title']);
}
When I do I receive the error message:
Call to a member function set_page_title() on a non-object
So what am I missing?
It means that $objPage is not an instance of an object. Can we see the code you used to initialize the variable?
As you expect a specific object type, you can also make use of PHPs type-hinting featureDocs to get the error when your logic is violated:
function page_properties(PageAtrributes $objPortal) {
...
$objPage->set_page_title($myrow['title']);
}
This function will only accept PageAtrributes for the first parameter.
There's an easy way to produce this error:
$joe = null;
$joe->anything();
Will render the error:
Fatal error: Call to a member function anything() on a non-object in /Applications/XAMPP/xamppfiles/htdocs/casMail/dao/server.php on line 23
It would be a lot better if PHP would just say,
Fatal error: Call from Joe is not defined because (a) joe is null or (b) joe does not define anything() in on line <##>.
Usually you have build your class so that $joe is not defined in the constructor or
Either $objPage is not an instance variable OR your are overwriting $objPage with something that is not an instance of class PageAttributes.
It could also mean that when you initialized your object, you may have re-used the object name in another part of your code. Therefore changing it's aspect from an object to a standard variable.
IE
$game = new game;
$game->doGameStuff($gameReturn);
foreach($gameArray as $game)
{
$game['STUFF']; // No longer an object and is now a standard variable pointer for $game.
}
$game->doGameStuff($gameReturn); // Wont work because $game is declared as a standard variable. You need to be careful when using common variable names and were they are declared in your code.
function page_properties($objPortal) {
$objPage->set_page_title($myrow['title']);
}
looks like different names of variables $objPortal vs $objPage
I recommend the accepted answer above. If you are in a pinch, however, you could declare the object as a global within the page_properties function.
$objPage = new PageAtrributes;
function page_properties() {
global $objPage;
$objPage->set_page_title($myrow['title']);
}
I realized that I wasn't passing $objPage into page_properties(). It works fine now.
you can use 'use' in function like bellow example
function page_properties($objPortal) use($objPage){
$objPage->set_page_title($myrow['title']);
}
I'm a little confused about the situation shown in this code...
class DirEnt
{
public function PopulateDirectory($path)
{
/*... code ...*/
while ($file = readdir($folder))
{
is_dir($file) ? $dtype = DType::Folder : $dtype = Dtype::File;
$this->push_back(new SomeClass($file, $dtype));
}
/*... code ...*/
}
//Element inserter.
public function push_back($element)
{
//Insert the element.
}
}
Why do I need to use either $this->push_back(new SomeClass($file, $dtype)) or self::push_back(new SomeClass($file, $dtype)) to call the member function push_back? I can't seem to access it just by doing push_back(new SomeClass($file, $dtype)) like I would have expected. I read When to use self over $this? but it didn't answer why I need one of them at all (or if I do at all, maybe I messed something else up).
Why is this specification required when the members are both non-static and in the same class? Shouldn't all member functions be visible and known from other member functions in the same class?
PS: It works fine with $this-> and self:: but says the functions unknown when neither is present on the push_back call.
$this->push_back will call the method as part of the CURRENT object.
self::push_back calls the method as a static, which means you can't use $this within push_back.
push_back() by itself will attempt to call a push-back function from the global scope, not the push_back in your object. It is not an "object call", it's just a plain-jane function call, just as calling printf or is_readable() within an object calls the usual core PHP functions.
I cant seem to access it just by doing push_back(new SomeClass($file, $dtype)) like I would have expected.
This way you call push_back() as a function. There is no way around $this (for object methods) or self::/static:: (for class methods), because it would result into ambiguity
Just remember: PHP is not Java ;)
You can access like this
public static function abc($process_id){
return 1;
}
public static function xyz(){
$myflag=self::abc();
return $myflag;
}
output : 1