How to reference a static function inside class in php? - php

I'am trying to make a reference to a static function inside a class:
class Test {
function __construct() {
$this->fn1 = self::fn2;
}
public static function fn2() {
}
}
then i get this error:
Undefined class constant 'fn2'
why?

Not sure if this is what you want, but at least this might give you a hint:
<?php
class Test {
function __construct() {
$this->fn = function(){
return self::realFn();
};
}
public function callFn (){
$fn = $this->fn ;//yes, assigning to a var first is needed. You could also use call_user_func
$fn();
}
public static function realFn() {
echo 'blah';
}
}
$x = new Test();
$x->callFn();
You can test it here: https://3v4l.org/KVohi

You have defined a static function:
Test {
function__construct()
{
$this->fn1 = self::fn2();
}
public static function fn2()
{
}
}

Updated
If you want to assign a function to a variable, it is best to do this
with annonymous aka lambda functions since they are first class citizens and may be freely passed, returned and assigned. PHP is not unique in dealing with static method references in this fashion as JAVA implements them similarly:
Method references ... are compact, easy-to-read lambda expressions for
methods that already have a name.
You may create an anonymous function based on a callable in PHP, and so the OP may wish to do as follows, which PHP 7.1.10 or higher supports:
<?php
class Test {
public static function fn2() {
return __METHOD__;
}
public static function getClosure (){
return Closure::fromCallable(["Test","fn2"]);
}
}
echo Test::getClosure()(),"\n";
See live code here
In this example an anonymous function is created and returned by the static getClosure method. When one invokes this method, then it returns the closure whose content is the same as static method fn2. Next, the returned closure gets invoked which causes the name of static method fn2 to display.
For more info re closures from callables, see the Manual and the RFC.
With PHP 7 on up, you may create a complex callable. In the code below the complex callable is an invocable array:
<?php
class foo
{
public static function test()
{
return [__CLASS__, 'fn2'];
}
public static function fn2()
{
echo __METHOD__;
}
}
echo foo::test()();
See live code.
Note: Starting with PHP 7.0.23 you could create a complex callable using a string containing the class and method names separated by the double colon aka paaamayim nekudotayim; see here.
A solution that has broader PHP support is as follows:
<?php
class Test {
public static function fn2() {
return __METHOD__;
}
public static function tryme(){
return call_user_func(["Test","fn2"]);
}
}
// return closure and execute it
echo Test::tryme();
See live code

Related

How do I point to another function? Is this possible?

The object is to make the name of the function shorter.
I have a function called somedescriptivefunctionName.
function somedescriptivefunctionName($a) {
echo $a;
}
I want to assign it to $this->f so that I do not litter the code with long names.
$this->f('Yahoo!!'); // will echo 'Yahoo!!'
e.g. I imagine something like this:
$this->f = $this->somedescriptivefunctionName; // wrong way
Is this possible?
Of course I could make a new function f, and return somedescriptivefunctionName(). But this is not the point.
You will store somewhere the string
$f = "somedescriptivefunctionName";
and then call the function by specifying its name in curly brackets:
$this->{$f}('Yahoo!!');
EDIT
According to the comment section, the aim is to call a method of an instance of another class by the same name. You can extend the config class to achieve a somewhat similar behavior, but I think that's not acceptable as a solution in this case. You can convert your class into a decorator, like
class SomeClassDecorator
{
protected $_instance;
public function myMethod() {
return strtoupper( $this->_instance->someMethod() );
}
public function __construct(SomeClass $instance) {
$this->_instance = $instance;
}
public function __call($method, $args) {
return call_user_func_array(array($this->_instance, $method), $args);
}
public function __get($key) {
return $this->_instance->$key;
}
public function __set($key, $val) {
return $this->_instance->$key = $val;
}
// can implement additional (magic) methods here ...
}
The code above was copied from Gordon's amazing answer here: How to add a method to an existing class in PHP?
An evolution of this idea could be to create a decorator for your config class as a base class and extend that base class for your classes that are configured by this, so you will implement a single decorator and (re)use it.
You can bind a property to a closure and invoke the property as a method:
class T{
private $f;
function abcdefghijklmnopqrstuvwxyz($param){
echo $param;
}
function __construct(){
$this->f = fn() => $this->abcdefghijklmnopqrstuvwxyz(...func_get_args());
}
function doWork() {
($this->f)('hello');
$g = $this->f;
$g('world');
}
}
(new T())->doWork();
In this code, the class f property is bound to a closure via an arrow function, which became available as of PHP 7.4, and we can dynamically get the arguments passed via func_get_args. If you are using a version less than 7.4 you can also just use a regular anonymous function.
Unfortunately, do to name resolution issues, properties cannot be invoked as methods without using an extra set of parentheses which means you have to do ($this->f)('hello'). If you want to skip that, you can further assign the class property to a local variable which can then be invoked normally as the $g is done.
edit
Here's a version of the constructor that doesn't use arrow functions, it is invoked in the same way.
function __construct()
{
$this->f = function () {
return $this->abcdefghijklmnopqrstuvwxyz(...func_get_args());
};
}

Correct way of using polyporphism in php?

I'm new to object oriented php. And if there are no functions in the method testing() in the HumanClass, should i declare them as abstract?
<?php
class HumanClass
{
private $legs;
private $hands;
public function __construct($legs, $hands)
{
$this->legs = $legs;
$this->hands = $hands;
}
public function testing()
{
}
}
class StudentClass extends HumanClass
{
private $books;
public function __construct($legs, $hands, $books)
{
parent::__construct($legs, $hands);
$this->books = $books;
}
public function testing()
{
echo "StudentClass called.";
}
}
function callClass(HumanClass $c)
{
$c->testing();
}
$example = new StudentClass(4, 2, 1);
callClass($a);
?>
Is it possible to have something like this?
echo $a->testing();
instead of having another method to call testing().
Given the code that you give, it's far from clear what the testing() function is supposed to do other than just exist for you to try things. The answer to that will also determine whether the versions in the baseclass should remain there as empty function.
There are other options, too, e.g. that the derived class first invokes the baseclass (extending), or that the baseclass doesn't contain an abstract or concrete such function but only the derived one does. Which to choose is up to the informed programmer to decide.

PHP Closure On Class Instance

If I have a class like:
class MyClass
{
public function foo()
{
echo "foo";
}
}
And then outside of the class instantiate it and try to create an anonymous function in it:
$mine = new MyClass();
$mine->bar = function() {
echo "bar";
}
And then try to call it like $mine->bar(), I get:
Fatal error: Call to undefined method MyClass::bar() in ...
How can I create an anonymous function / closure on a class instance?
Aside: Before you tell me I should rethink my logic or use interfaces and OOP properly, in my case, it's a convenience method that applies to this specific instance of a bastardized class in an attempt to clean-up a legacy procedural application. And yes, I'm using PHP 5.3+
See my blog article here: http://blog.flowl.info/2013/php-container-class-anonymous-function-lambda-support/
You need to add a magic __call function:
public function __call($func, $args) {
return call_user_func($this->$func, $args);
}
The problem is that within this construct you can call private methods from public scope.
I suggest not to simply add new variables to a class that are not defined. You can avoid this using magic __set functions and catch all undefined variables in a container (= array, like in my blog post) and change the call_user_func behaviour to call only inside the array:
// inside class:
public $members = array();
public function __call($func, $args) {
// note the difference of calling only inside members:
return call_user_func($this->members[$func], $args);
}
__call
This will work.
class Foo {
public $bar;
public function __construct()
{
$this->bar = function()
{
echo 'closure called';
};
$this->bar();
}
public function __call($method, $args) {
return call_user_func($this->$method, $args);
}
}
new Foo();
The function IS being created.
PHP has a problem with calling it.
Dirty, but works:
$f = $mine->bar;
$f();

Use Class property inside of a method's function

I'm trying to use myVar inside my of a method's function. I have already tried adding global but still nothing. I know this is probably basic but I can't seem to find it.
class myClass{
public $myVar;
public function myFunction() {
function myInnerFunction() {
//how do I use this variable here
echo $this->myVar;
}
}
}
Whenever I try using $this I get this error: 'Using $this when not in object context in...'
You should use $this->myVar
See the PHP Documentation - The Basics
<?php
class SimpleClass
{
// property declaration
public $var = 'a default value';
// method declaration
public function displayVar() {
echo $this->var;
}
}
?>
The pseudo-variable $this is available when a method is called from
within an object context. $this is a reference to the calling object
(usually the object to which the method belongs
Update:
In your new code sample, myInnerFunction is a nested function and is not accessible until the myFunction method is called. Once the myFunction method is called, the myInnerFunction becomes part of the global scope.
Maybe this is what you are looking for:
class myClass{
public $myVar;
public function myFunction() {
}
function myInnerFunction() {
//how do I use this variable here
echo $this->myVar;
}
}
Inner functions like myInnerFunction are always global in scope, even if they are defined inside of a member function in a class. See this question for another similar example
So, to PHP, the following are (almost) equivalent:
class myClass{
public $myVar;
public function myFunction() {
function myInnerFunction() {
//how do I use this variable here
echo $this->myVar;
}
}
}
And
class myClass{
public $myVar;
public function myFunction() {
}
}
function myInnerFunction() {
//how do I use this variable here
echo $this->myVar;
}
Hopefully the second example illustrates why $this is not even in scope for myInnerFunction. The solution is simply to pass the variable as a parameter to the function.
Pass it as an argument to the inner function.
You can use ReflectionProperty:
$prop = new ReflectionProperty("SimpleClass", 'var');
Full example:
class myClass{
public $myVar;
public function myFunction() {
function myInnerFunction() {
//how do I use this variable here
$prop = new ReflectionProperty("SimpleClass", 'myVar');
}
}
}
The solution above is good when you need each instance to have an own value. If you need all instances to have a same you can use static:
class myClass
{
public static $myVar = "this is my var's value";
public function myClass() {
echo self::$myVar;
}
}
new myClass();
see here

call a static method inside a class?

how do i call a static method from another method inside the same class?
$this->staticMethod();
or
$this::staticMethod();
self::staticMethod();
More information about the Static keyword.
Let's assume this is your class:
class Test
{
private $baz = 1;
public function foo() { ... }
public function bar()
{
printf("baz = %d\n", $this->baz);
}
public static function staticMethod() { echo "static method\n"; }
}
From within the foo() method, let's look at the different options:
$this->staticMethod();
So that calls staticMethod() as an instance method, right? It does not. This is because the method is declared as public static the interpreter will call it as a static method, so it will work as expected. It could be argued that doing so makes it less obvious from the code that a static method call is taking place.
$this::staticMethod();
Since PHP 5.3 you can use $var::method() to mean <class-of-$var>::; this is quite convenient, though the above use-case is still quite unconventional. So that brings us to the most common way of calling a static method:
self::staticMethod();
Now, before you start thinking that the :: is the static call operator, let me give you another example:
self::bar();
This will print baz = 1, which means that $this->bar() and self::bar() do exactly the same thing; that's because :: is just a scope resolution operator. It's there to make parent::, self:: and static:: work and give you access to static variables; how a method is called depends on its signature and how the caller was called.
To see all of this in action, see this 3v4l.org output.
This is a very late response, but adds some detail on the previous answers
When it comes to calling static methods in PHP from another static method on the same class, it is important to differentiate between self and the class name.
Take for instance this code:
class static_test_class {
public static function test() {
echo "Original class\n";
}
public static function run($use_self) {
if($use_self) {
self::test();
} else {
$class = get_called_class();
$class::test();
}
}
}
class extended_static_test_class extends static_test_class {
public static function test() {
echo "Extended class\n";
}
}
extended_static_test_class::run(true);
extended_static_test_class::run(false);
The output of this code is:
Original class
Extended class
This is because self refers to the class the code is in, rather than the class of the code it is being called from.
If you want to use a method defined on a class which inherits the original class, you need to use something like:
$class = get_called_class();
$class::function_name();
In the later PHP version self::staticMethod(); also will not work. It will throw the strict standard error.
In this case, we can create object of same class and call by object
here is the example
class Foo {
public function fun1() {
echo 'non-static';
}
public static function fun2() {
echo (new self)->fun1();
}
}
call a static method inside a class
className::staticFunctionName
example
ClassName::staticMethod();

Categories