Add regular not antonymous function to class - php

I wanted to add functions to class, those functions are in separate file(s), those functions contain ($this).
class myClass {
private $myFunctions=array(); // will contain two keys (title, function_object)
private $var;
public function __construct() {
$this->var = 'Hello world';
}
public function add_function($title, $func) {
$this->myFunctions[$title] = $func;
}
}
function add($x, $y) {
echo $this->var;
return $x + $y;
}
$class = new myClass;
$class->add_function('add', 'add()');
echo $class->add(1,2);
my goal is to add regular functions (not anonymous functions) to the class or to assign those function(s) to a var which can be passed to the class!
Can this be achieved ?

You must have to understand the oops concepts here.
$this refers to your current class / object. So all functions inside a class will be able to access $this ( Current Object ).
But the function declared out side of class can not use $this of that object. (Are you clear up to here.)
But anyways nothing is impossible.
You can achieve your goal in at-least 2 ways.
2) You can use trait to implement multiple inheritance.
it will be like this
trait commonFunctions
{
function add($a, $b)
{
$this->result = $a + $b;
return $this;
}
}
class myClass
{
use commonFunctions;
public function myClassFunction()
{
//
}
}
2 ) Or you can follow below code. Source php.net
<?php
class A {
function __construct($val) {
$this->val = $val;
}
function getClosure() {
//returns closure bound to this object and scope
return function() { return $this->val; };
}
}
$ob1 = new A(1);
$ob2 = new A(2);
$cl = $ob1->getClosure();
echo $cl(), "\n";
$cl = $cl->bindTo($ob2);
echo $cl(), "\n";
Here __call will be called when undeclared method is being called. So you can dynamically append methods to class by this way.
Of course you can polyfill your object in javascript like way. But keep in mind you need to use Reflection to bind this to closure.
<?php
class A {
private $dynamic_functions=[];
public function __call($method, $args=[])
{
if(isset($this->dynamic_functions[$method]) && $this->dynamic_functions[$method] instanceof \Closure)
{
$cl = $this->dynamic_functions[$method]->bindTo($this);
return call_user_func_array($cl, $args);
}
else
{
die("Wrong method, Not yet polyfilled.");
}
}
public function __set($property, $value)
{
$this->dynamic_functions[$property] = $value;
}
}
$a = new A;
$a->sum = function($a,$b){
// var_dump($this); will give you current instance of A
return $a+$b;
};
echo $a->sum(5, 3);

It is possible, but their are limits. When calling undefined methods on an object, PHP checks if there is a magic method named __call:
public mixed __call ( string $name , array $arguments )
This function then receives the function name, and the list of arguments. For your construction you could use
public function __call($name, $args) {
// invokes the function with all arguments:
// e.g: function_name($arg[0], $arg[1], ...)
return call_user_func_array($this->myFunctions[$name], $args);
}
There is just one problem, namely you cannot use $this within your anonymous functions. In python this problem got solved by passing the instance as the first argument (which is usually called self). We can build something similar by adding the instance to the argument list:
public function __call($name, $args) {
// we add the instance at the beginning of the argument list
array_unshift($args, $this);
return call_user_func_array($this->myFunctions[$name], $args);
}
Now you could do something like
function bork($instance, $a, $b) {
return $a*$b;
}
$class = new myClass;
$class->add_function('derp', 'bork');
$class->add_function('add', function($instance, $x, $y) {
echo $instance->var;
return $x + $y;
});
echo $class->derp(1,2);
echo $class->add(35,34534);
If you have already some function which does not have $instance as a first argument, you could wrap it
function my_cool_existing_function($bla) {
echo $bla.$bla;
}
$class->add_function('super_bork', function($instance, $bla) {
return my_cool_existing_function($bla);
});

No, you can't add a function to a class like this. You can extend your class with other class having this function add(). This way inherited class will have parent's function add().

Related

PHP - Call function from after call to another function in the class

I have this class:
class myClass
{
function A() {
$x = "Something ";
return $x;
}
function B() {
return "Strange";
}
}
But I want to call the function like this:
myClass()->A()->B();
How can i do that without return the class itself(return $this)?
In order to achieve method chaining, your methods from the chain (except the last one) must return an object (in many cases and also in yours $this).
If you would want to build a string with method chaining, you should use a property to store it. Quick example:
class myClass
{
private $s = "";
function A() {
$this->s .= "Something ";
return $this;
}
function B() {
$this->s .= "Strange";
return $this;
}
function getS() {
return $this->s;
}
}
// How to use it:
new myClass()->A()->B()->getS();

How to define a callback with parameters without closure and use in PHP?

In PHP in order to define a callback a closure can be used and the tool for passing static parameters is the use directive.
class MyClass {
public function foo($x) {
echo $x;
}
public function bar() {
$x = '123';
$callback = function () use ($x) {
$this->foo($x);
};
$callback();
}
}
$myClass = new MyClass();
$myClass->bar();
Is it possible / How to avoid the anonymous function and replace it by a method?
class MyClass {
public function foo($x) {
echo $x;
}
public function baz() {
$x = '567';
// There is no function with the name create_user_func.
// Just to show, what I'm looking for.
$callback = create_callback([$this, 'foo'], $params = [$x]);
$callback();
}
}
$myClass = new MyClass();
$myClass->baz();
EDIT:
Some additional / backgroud info (to make clear, what I want to achieve and why -- and to avoid misanderstandings):
In my concrete case I need to pass the callback to a method of a framework. That means: I cannot / may not affect the way it gets called.
The method accepts only the callback itself, no arguments for the callback. That means, the callback has to "know"/provide the static parameters (and their values) it needs.
It's exactly, what the use directive solves. But I have multiple callback definitions in my method, and the method is getting long. So I want to move the logic of the callbacks to separate methods.
But I have multiple callback definitions in my method, and the method is getting long. So I want to move the logic of the callbacks to separate methods.
This is a perfect example for the magic method __invoke()
For each callback you need, extract the functionality and the properties it uses into a new class. Put the code into the __invoke() method of the new class, initialize all the properties it needs into its __construct() and you're ready to go.
The code:
class MyClass {
public function bar() {
$x = '123';
// Create the callback, pass the values it needs to initialize
$callback = new ActionFoo($x);
// Call the callback without arguments
$callback();
}
}
class ActionFoo {
private $x;
public function __construct($x) {
$this->x = $x;
}
public function __invoke() {
echo($this->x);
}
}
$myClass = new MyClass();
$myClass->bar();
I guess it's fair to say that you're trying to emulate Javascript's bind method. The problem with this in PHP is that functions are not first class citizens or objects, so something like ->bind($x) is not possible. There's also no way to pass additional parameters for a callable. So you're going to have to wrap it in something.
A more reusable method would be to write an appropriate class:
class CallbackWrapper {
protected $callable,
$args;
public function __construct(callable $callable, array $args) {
$this->callable = $callable;
$this->args = $args;
}
public function __invoke() {
call_user_func_array($this->callable, $this->args);
}
}
giveMeACallback(new CallbackWrapper([$this, 'foo'], [$x]));
Or you just simplify the construction of anonymous functions:
function make_callback(callable $callable, array $args) {
return function () use ($callable, $args) {
return call_user_func_array($callable, $args);
};
}
giveMeACallback(make_callback([$this, 'foo'], [$x]));
There are many ways to achieve this.
Using a helper function.
Code:
class MyClass {
private $x;
public function foo() {
echo $this->x;
}
public function bar() {
$this->x = '123';
anon($this);
}
}
$myClass = new MyClass();
$myClass->bar();
function anon($obj) {
$obj->foo();
}
Using call_user_func.
Code:
class MyClass {
private $x;
public function foo() {
echo $this->x;
}
public function bar() {
$this->x = '123';
call_user_func([$this, 'foo']);
}
}
$myClass = new MyClass();
$myClass->bar();
If for some reason you don't want to use member variables, you can pass the arguments with call_user_func_array.
Code:
class MyClass {
private $x;
public function foo($x) {
echo $x;
}
public function bar() {
$x = '123';
call_user_func_array([$this, 'foo'], [$x]);
}
}
$myClass = new MyClass();
$myClass->bar();

Is there a way to catch undefined globals in PHP, and provide a value, like autoload, but for variables?

We have a lot of existing code that, rather than creating an instance of a class, or using a static function on that class, will call the method on a global singleton of that class.
For example (stringclass.php):
class String {
function endsWith($str, $search) {
return substr($str, -strlen($search)) == $search;
}
}
$STRING_OBJECT = new String();
then it will use this in the following way:
include_once("stringclass.php");
if ($STRING_OBJECT->endsWith("Something", "thing")) {
echo "It's there\n";
}
I realise that this is not a very sensible way of calling the function, but I was wondering if we could fix all the places where people have forgotten to include the right classes using an auto-loader, without changing all the code that uses these singletons. It would detect the use of an undeclared global, and include the correct class file based on the name of the global that was being referenced.
You can use the ArrayAccess interface
http://php.net/manual/en/class.arrayaccess.php
class Ztring implements arrayaccess
{
private $container = array ();
public function offsetSet ($offset, $value)
{
$this->container[$offset] = $value;
}
public function offsetGet ($offset)
{
// exception
if ($offset == 'something')
{
return 'works!';
}
return $this->container[$offset];
}
public function offsetExists ($offset)
{
return isset($this->container[$offset]);
}
public function offsetUnset ($offset)
{
unset ($this->container[$offset]);
}
}
$x = new Ztring ();
$x['zzz'] = 'whatever';
echo $x['zzz']."\n";
echo $x['something']."\n";

How to call the __invoke method of a member variable inside a class

PHP 5.4.5, here. I'm trying to invoke an object which is stored as a member of some other object. Like this (very roughly)
class A {
function __invoke () { ... }
}
class B {
private a = new A();
...
$this->a(); <-- runtime error here
}
This produces a runtime error, of course, because there's no method called a. But if I write the call like this:
($this->a)();
then I get a syntax error.
Of course, I can write
$this->a->__invoke();
but that seems intolerably ugly, and rather undermines the point of functors. I was just wondering if there is a better (or official) way.
There's three ways:
Directly calling __invoke, which you already mentioned:
$this->a->__invoke();
By assigning to a variable:
$a = $this->a;
$a();
By using call_user_func:
call_user_func($this->a);
The last one is probably what you are looking for. It has the benefit that it works with any callable.
FYI in PHP 7+ parenthesis around a callback inside an object works now:
class foo {
public function __construct() {
$this -> bar = function() {
echo "bar!" . PHP_EOL;
};
}
public function __invoke() {
echo "invoke!" . PHP_EOL;
}
}
(new foo)();
$f = new foo;
($f -> bar)();
Result:
invoke!
bar!
I know this is a late answer, but use a combination of __call() in the parent and __invoke() in the subclass:
class A {
function __invoke ($msg) {
print $msg;
}
}
class B {
private $a;
public function __construct() { $this->a = new A(); }
function __call($name, $args)
{
if (property_exists($this, $name))
{
$prop = $this->$name;
if (is_callable($prop))
{
return call_user_func_array($prop, $args);
}
}
}
}
Then you should be able to achieve the syntactic sugar you are looking for:
$b = new B();
$b->a("Hello World\n");

Does an overloaded __get need to manage all member variables?

I am creating a __get() function for a class to control access to my private member variables. Do I need to design the function to handle all possible member value reads or can I not write it for members that are public? Also, I am assuming that classes that inherit this class will use my __get() function to access private members.
class ClassA{
private $collection = array();
public $value;
function __get($item){
return $collection[$item];
}
No, you don't.
class A {
public $foo = 'bar';
private $private = array();
public function __get($key) {
echo 'Called __get() at line #' ,__LINE__, ' with key {', $key ,'}',"\n";
return $this->private[$key];
}
public function __set($key, $val) {
$this->private[$key] = $val;
}
}
$a = new A();
var_dump($a->foo);
$a->bar = 'baz';
var_dump($a->bar);
And yes, it will:
class B extends A { private $private = array(); }
$b = new B();
var_dump($b->bar);
Well, your code would fail on private items not set in your array. But then again, you can use this as a way to deal with what's in and out of your array, as such ;
function __get($item){
if ( isset ( $collection[$item] ) )
return $collection[$item];
else {
try {
return $this->$item ; // Dynamically try public values
} catch (Exception $e) {
$collection[$item] = 0 ; // Make it exist
}
}
}
Classes that inherit your calls will use this __get(), but can be overridden, so use parent::__construct() for explicity. Also note that these cannot be static. Further reading.
First of all PHP searches for property name in class definition and tries to return its value. If there's no property - PHP tries to call __get($var) and here you can return anything you want. This is a little confusing behavior for those, who know Java-like getters/setters where you have to define them for every class member you want to access.
When it's comfortable to use Java-like getters/setters - you may write something like this:
public function __set($var, $value)
{
if (method_exists($this, $method = "_set_" . $var))
{
call_user_func(array($this, $method), $value);
}
}
public function __get($var)
{
if (method_exists($this, $method = "_get_" . $var))
{
return call_user_func(array($this, $method), $value);
}
}
and then use this code by defining custom getters/setters
protected function _get_myValue()
{
return $this->_myValue;
}
protected function _set_myValue($value)
{
$this->_myValue = $value;
}
and access to defined methods this way:
$obj->myValue = 'Hello world!';

Categories