PHP create_function Instance variable - Unable to call anonymous function: Follow up - php

This is somewhat a follow up to a previous question - but I've distilled the question down and have the "works" vs. "doesn't work" cases narrowed down much more precisely.
My Goal:
I have a class MyClass that has an instance variable myFunction. Upon creating a MyClass object (instantiating), the constructor assigns the instance variable myFunction with the result of a call to create_function (where the code and args come from a db call).
Once this object of type MyClass is created (and stored as an instance variable of another class elsewhere) I want to be able to call myFunction (the instance variable anonymous function) from "anywhere" that I have the MyClass object.
Experimental Cases -- below is my highly simplified test code to illustrate what works vs. what doesn't (i.e. when the expected functionality breaks)
class MyClass extends AnotherClass {
public $myFunction;
function __construct() {
$functionCode = 'echo "NyanNyanNyan";';
$this->myFunction();
/*Now the following code works as expected if put in here for testing*/
$anonFunc = $this->myFunction;
$anonFunc(); //This call works just fine (echos to page)!
/*And if i make this call, it works too! */
self::TestCallAnon();
}
public function TestCallAnon() {
$anonFunc2 = $this->myFunction;
$anonFunc2();
}
}
However, if I do the following (in another file, it errors saying undefined function () in... within the Apache error log.
//I'm using Yii framework, and this is getting the user
//objects instance variable 'myClass'.
$object = Yii::app()->user->myClass;
$object->TestCallAnon(); // **FAILS**
or
$func = $object->myFunction;
$func(); // ** ALSO FAILS **
In addition, several variations of calls to call_user_func and call_user_func_array don't work.
If anyone is able to offer any insight or help that would be great :).
Thanks in advance!

You can't pass references to functions around in PHP like you can in for instance JavaScript.
call_user_func has limited functionality. You can use it like so:
class MyClass {
function func() {}
static function func() {}
}
function myfunc() {}
$i = new MyClass();
call_user_func("myfunc", $args);
call_user_func(array($i, "func"), $args);
call_user_func(array(MyClass, "staticFunc"), $args);

I ended up solving this issue via a workaround that ended up being a better choice anyways.
In the end I ended up having a static class that had a method to randomly return one of the possible identifiers, and then another method which accepted that identifier to build the anonymous function upon each class.
Slightly less elegant than I would like but it ends up working well.
Thanks to everyone for your efforts.

Related

Inheritance bug in PHP [duplicate]

I've been looking at some code and am having a hard time working out variable declaration in php classes. Specifically it appears that the code i'm looking at doesn't declare the class variables before it uses them. Now this may be expected but I can't find any info that states that it is possible. So would you expect this:
class Example
{
public function __construct()
{
$this->data = array();
$this->var = 'something';
}
}
to work? and does this create these variables on the class instance to be used hereafter?
This works the same as a normal variable declaration would work:
$foo = 'bar'; // Created a new variable
class Foo {
function __construct() {
$this->foo = 'bar'; // Created a new variable
}
}
PHP classes are not quite the same as in other languages, where member variables need to be specified as part of the class declaration. PHP class members can be created at any time.
Having said that, you should declare the variable like public $foo = null; in the class declaration, if it's supposed to be a permanent member of the class, to clearly express the intent.
So would you expect this: (code sample) to work?
Yes. It's pretty bad practice (at least it makes my C++ skin crawl), but it wouldn't surprise me in the slightest. See example 2 in the following page for an example of using another class without declaring it beforehand. http://www.php.net/manual/en/language.oop5.basic.php It will throw an error if E_STRICT is enabled.
And does this create these variables on the class instance to be used hereafter?
Yep. Ain't PHP Fun? Coming from a C++/C# background, PHP took a while to grow on me with its very loose typing, but it has its advantages.
That's completely functional, though opinions will differ. Since the creation of the class member variables are in the constructor, they will exist in every instance of the object unless deleted.
It's conventional to declare class member variables with informative comments:
class Example
{
private $data; // array of example data
private $var; // main state variable
public function __construct()
{
$this->data = array();
$this->var = 'something';
}
}

PHP: Overwriting of static methods does not work as expected

I have two php classes: TestUK and TestFR, which extends TestUK.
Both classes are used to generate requests to two different domains. But something is going wrong with the inheritence, and I fail to understand why.
I have one method named "get_domain", which is overwritten to get the domain that should actually be used. If I call it directly via TestFR::get_domain(), i receive the expected result. But if I call a method that is not overwritten by TestFR, but which uses self::get_domain(), I receive the wrong domain.
If I simply copy-and-paste the method do_stuff from TestUK to TestFR, then I get the expected result. But copy-pasting identical (!) code is just what I was trying to avoid.
What is the reason for this? I do not have that much experience with class inheritence in PHP, but I would have expected this to work without problems. Or is my approch completely flawed?
<?php
class TestUK {
const DOMAIN_UK = 'http://www.domain.co.uk';
const DOMAIN_FR = 'http://www.domain.fr';
static function get_domain(){
return self::DOMAIN_UK;
}
static function do_stuff(){
echo self::get_domain();
}
}
class TestFR extends TestUK {
static function get_domain(){
return self::DOMAIN_FR;
}
}
// Works as intended:
// Expected and actual output: http://www.domain.fr
echo TestFR::get_domain();
// Does NOT work as intendes:
// Expected Output: http://www.domain.fr
// Actual Output: http://www.domain.co.uk
TestFR::do_stuff();
?>
This is because the keyword self refers to the class where it appears in, not to the class on which the method was called. For the latter functionality you will have to use late static binding with the static keyword:
static function do_stuff(){
echo static::get_domain();
}
That said, this code smells really bad. Why is everything static and not simply an instance method? Why is TestFR extending TestUK instead of both extending an abstract base class Test?
It would be much better to convert everything to non-static methods, and as a bonus your problem would immediately disappear.
call it like (if you are using php >= 5.3
static::get_domain();

Using -> with a static function

Hi I'm a bit of a newbie to OOP, i just have a quick question: say I have a function in a class declared as
class House
{
public static function hasAlcohol()
{
// Do Something
}
}
I know i can call this as
House::hasAlcohol()
However, i would also like to know if its okay with coding standards and PHP and if it would be error free to call hasAlcohol() from an instance of house (i tried it and got no errors), for example
$house = new House();
$house->hasAlcohol();
As this has caused several problems for me in the past: Yes, it is valid code. Should you do it? No. It gives the impression that the call is non-static and will most likely cause grief for people working on your code later on. There is no reason to make your code ambiguous.
This used to be possible, but the latest versions of PHP will throw an error, if I remember correctly. You should call static functions statically. You can do $house::hasAlcohol() though.
This used to be possible, but the latest versions of PHP will throw an error, if I remember correctly. You should call static functions statically. You can do $house::hasAlcohol() though.
On a side note, should hasAlcohol really be static? From the name it appears it should be an instance method.
A more recommended pattern if you need constant access to a method is to use a static constructor and get an instance (even if it's a "blank" or "empty") instance to that class. So in the example you've shown, it might be better to have a method like this:
class House
{
public function instance()
{
return new House;
}
public function hasAlcohol()
{
// Do Something
}
}
Then if you ever needed to make a call to "hasAlcohol()" where you don't need an instance for any other purpose, you can do a one-off like so:
House::instance()->hasAlcohol();
or you can instantiate it like in your example:
$house = new House;
$house->hasAlcohol();
or, better yet, use your new factory method:
$house = House::instance();
$house->hasAlcohol();

PHP and Python static methods in objects, two different worlds...?

i'm php coder, trying to get into python world, and it's very hard for me.
Biggest enjoy of static methods in php is automatic builder of instance. No need to declare object, if you needed it once, in every file (or with different constructor params , in one line)
<?php
class Foo {
function __constructor__(){
$this->var = 'blah';
}
public static function aStaticMethod() {
return $this->var;
}
}
echo Foo::aStaticMethod();
?>
we can call constructor from static method don't we? and we can access everything in class as it would be simple method ... we can even have STATIC CONSTRUCTOR in php class and call it like so: Object::construct()->myMethod(); (to pass different params every time)
but not in python???? #staticmethod makes method in class a simple function that doesn't see totally anything ??
class socket(object):
def __init__(self):
self.oclass = otherclass()
print 'test' # does this constructor called at all when calling static method??
#staticmethod
def ping():
return self.oclass.send('PING') # i can't access anything!!!
print Anidb.ping()
I can't access anything from that god damned static method, it's like a standalone function or something like this..??
Maybe I'm using the wrong decorator? Maybe there's something like php offers with static methods in python?
1) Please tell why static methods is isolated
2) Please tell me how to make the same behavior like php static methods have.
3) Please tell me alternative practical use of this, if php static methods behavior is a bad thing
P.s. the goal of all this to write totally less code as much as possible.
P.p.s Heavy commenting of sample code is appreciated
Thank you.
static methods in PHP are not as you believe, they can't access to instance members. No $this! with them.
<?php
class Foo {
public static $var = 'foo ';
function __construct(){
echo 'constructing ';
$this->var = 'blah ';
}
public function aMethod() {
return $this->var;
}
public static function aStaticMethod() {
#return $this->$var; -> you can't do that,
# $this can be accessed only in instance methods, not static
return self::$var;
}
}
$foo = new Foo();
echo $foo->aMethod();
echo Foo::aStaticMethod();
?>
Python has three kind of methods in objects static methods are like functions defined ouside classes, the only use to put them in object is to keep them with the class as helper functions. class methods can access only to variables defined in the class (decorator #classmethod). This is more or less what PHP calls static members or methods. The first parameter of such methods sould be cls, and content of class can be accessed through cls. Normal methods must get self as first parameter and are the only ones to be able to access to instance members.
If you want several objects of the same type you definitely need instances, and the other types are not what you are looking for. If you only have one instance of an object, you could use class methods instead (or PHP static methods).
But in most case you should not bother doing that if you don't know why and just stick with instances of objects and normal methods, doing otherwise is premature optimization and your code is likely to bite you later because of the many restrictions you introduce.
You want classmethod instead. That provides the class as the first argument.
EDIT:
class C(object):
foo = 42
#classmethod
def printfoo(cls):
print cls.foo
C.printfoo()
I see you've already accepted another answer, but I'm not sure that it will work with your code. Specifically, the oclass variable is only created for instances of the class, not for the class itself. You could do it like this:
class socket(object):
oclass = otherclass()
#classmethod
def ping(cls):
return cls.oclass.send('PING')
socket.ping()
However, using your existing code and removing all decorators, you could simply instantiate it and use a method on the same line:
socket().ping()

PHP5 Class scope quirks

Hey php gurus. I'm running into some bizarre class scope problems that clearly have to do with some quirk in php. Can anyone tell me what out-of-the-ordinary situations might give the following error...
Fatal error: Cannot access self:: when no class scope is active in MyClass.php on line 5
Now, obviously if I were to use self:: outside of the class, I'd get errors... but I'm not. Here is a simplified version of the situation...
//file1
class MyClass{
public static function search($args=array()){
$results = MyDbObject::getQueryResults("some query");
$ordered_results = self::stack($results); //Error occurs here
return $ordered_results;
}
public static function stack($args){
//Sort the results
return $ordered_results;
}
}
//file 2
include_once("MyClass.php");
$args = array('search_term'=>"Jimmy Hoffa");
$results = MyClass::search($args);
given this setup how can I get the error above? Here is what I've found so far...
MyClass::search($args) //does not give the error (usually)
call_user_func("MyClass::search"); // this gives the error!
Any other situations?
If I understand correctly, you are looking for Late Static Binding. This feature requires PHP version 5.3 at least.
You're not passing any parameters, but your method is looking for them. Try
call_user_func("MyClass::search", $args);
This works in php 5.3.1, but call_user_func("MyClass::search"); doesn't
Try this:
call_user_func(array('MyClass', 'search'));
See also example #4 on http://php.net/call_user_func
Your code seems fine. If there's something wrong with it, I must be missing the problem. It appears that your call to self:: is totally within the scope of a class! And a static scope, specifically, which is what self:: is for.
From the 3rd Edition of PHP Objects Patterns and Practice (an awesome book):
To access a static method or property from within the same class
(rather than from a child), I would use the self keyword. self is to
classes what the $this pseudo-variable is to objects. So from outside
the StaticExample class, I access the $aNum property using its class
name:
StaticExample::$aNum;
From within the StaticExample class I can use the self keyword:
class StaticExample {`
static public $aNum = 0;
static public function sayHello() {
self::$aNum++;
print "hello (".self::$aNum.")\n";
}
}
So, I am not sure why this code was failing. Perhaps a PHP bug? I came upon this error when actually trying to use self:: outside of the scope of a class-- my error looked like this:
public static function get_names() {
$machine_names = self::get_machine_names();
return array_map(function ($machine_name) {
$service_settings = self::get_settings_by_machine_name($machine_name);
return $service_settings . $machine_name;
},
$machine_names
);
}
So, I get the error because I use self:: within the scope of the closure. To fix the error, I could make that call to self::get_settings_by_machine_name() before the closure, and pass the results to the closure's scope with use.
Not sure what was happening in your code.

Categories