Is there an array-to-callable function? - php

Setting
Within SomeClass there is f2member taking two integer arguments and producing its sum. The test passes showing that the call actualy works and retrieves the expected result. Which is calling $gwith two parameters 1 and 1 returning 2.
Important: This works only for php 5.4.11 and upwards compatibility check
class SomeClass extends PHPUnit_Framework_TestCase
{
function f2member($a,$b)
{
return $a + $b;
}
/**
* #test
*/
public function test()
{
$g = array($this,'f2member');
$this->assertEquals(2, $g(1,1)); // squiggle line under $g
}
}
Problem
However, this produces a warning inside phpStorm on every method invocation and a squiggle line under $g:
Function name must be callable - string, Closure or class implementing __invoke, currently array
The origin of the warning is clear to me and now i am looking for ways to avoid these warnings.
A requirement is, that i dont want to change the style of calling the function. Another thing i don't want to do is to deactivate this warning.
I would rather prefer to wrap something around it, which provides the necessary information to the type system.
Attempt
I already encountered several solutions to remove the warnings. One is to define a user defined function, which only documents the required target type.
/**
* #param array $arr
*
* #return callable
*/
function callable_for($arr)
{
return $arr;
}
This returns an array, but also explicitly tells the type system what comes out of the callable_for function. With this type annotation in place phpStorm now stops complaining about this warning, although it still returns an array.
$g = callable_for(array($this,'f2member'));
Question
Isn't there something out of the box like my callable_for in php to achieve this? If the answer is no, then
i am looking for the most concise solution we can find.
I already tried looking on SO, php.net and google. Maybe, I just searched for the wrong word combinations, here are just two samples:
array to callable php
create callable method handle php
BigPicture
Just in case suspects arise this is a X/Y problem: I have another function taking a callable as a parameter. With closures it is very natural to define something, which can be invoked later on. However, how do i define a callable for a member or a static method without wrapping it in another delegation Closure? The array notation allows to be used to uniformly pass: closures or static/member method handles to my later function. I am now trying to find a concise solution to this, which comes close to this.

Thus, another advancement could be, to modify callable_for to take two arguments and wrap both responsibilities; to create the array and to document the target return type.
/**
* #param mixed $context
* #param string $method
*
* #return callable
*/
function callable_for($context, $method)
{
return array($context, $method);
}
Using this implementation raises the conciseness of $g's declaration to an acceptable level.
$g = callable_for($this,'f2member');
This function still returns an array, but the type system can use the given information to correctly treat this array for dynamic method invocation.

The question was asked four years ago but after some research I found the Closure::fromCallable method: https://www.php.net/manual/de/closure.fromcallable.php

Related

What are these mysterious things in defining methods?

Back to development after spending some years in a management position, I am dealing with a PHP code, which has some definitions that I cannot understand (looks like I am far beyond of PHP progress on these years). Can someone let me know what campaignDTO and ParamDTO do in this definition?
What will be returned from this method?
/**
* Creates a campaign
* #param campaignDTO $campaign
* #param ParamDTO $param
* #throws \Exception
* #return campaignDTO
*/
public function createCampaign(campaignDTO $campaign, ParamDTO $param)
{
}
Type declarations as per docs:
Type declarations allow functions to require that parameters are of a
certain type at call time. If the given value is of the incorrect
type, then an error is generated: in PHP 5, this will be a recoverable
fatal error, while PHP 7 will throw a TypeError exception.
These are type-hints for run-time validation. It tells the code to expect objects of class type campaignDTO and ParamDTO, or a class that extends from these.
If you pass in an array, or a string, or something that is not a class that is or extends capaignDTO then the code will throw an error.
The function, as it is, returns nothing.
According to the code-comment, it will return an object of type campaignDTO, which looks like the first parameter.

How to know if a function is called first time or not

I want to create a function such that if it is called the first time, it behaves differently and for rest of the time it behaves differently. Now to do this I know I can use a "state" variable. Some other techniques were also given here:
Check if function has been called yet
However I somehow got a hint from a colleague that debug_backtrace() can be used to solve this problem. I read about it but cannot understand how ? This function gives a stack trace of the function call. How can this tell if the function has been called first time or not ?
The exact code that baffles me is here:
/**
* Holds the states of first timers
* #var array
*/
private static $firstTimeCSS=array();
private static $firstTimeJS=array();
/**
* Tells whether it is the first time this function is called on
* ANY CLASS object or not. Useful for one-time scripts and styles
*
* #param string $class name optional. Usually you should send __CLASS__ to this, otherwise the instance ($this) class would be used.
* #return boolean
*/
final protected function IsFirstTime($class=null)
{
$t=debug_backtrace();
if ($t[1]['function']=="JS")
$arr=&self::$firstTimeJS;
else
$arr=&self::$firstTimeCSS;
if ($class===null)
$class=$this->Class;
if (isset($arr[$class]))
return false;
else
{
$arr[$class]=true;
return true;
}
}
I personally don't see how this is possible or why you would want to do it this way. I suspect debug_backtrace() is a lot more expensive than a static variable, to begin with.
The only backtrace characteristic that seems to change between calls is, as you pointed out, the line number (from where the function was called). And, that wouldn't even change if you ran the functions in, say, a loop, since they would all be called from the same line on each iteration.
Demonstration 1 (individual calls): CodePad
Demonstration 2 (loop): CodePad
If I were you, I'd stick with a state variable; as for your colleague, you could perhaps ask him to show you a code which demonstrates his methodology if you're curious as to how it works (I know I am!).
Edit (from comments): Basically, your colleague's debug_backtrace() method stores a boolean value in an array using the key of the class which is called.
In plain English, here's what happens:
Is the calling function called "JS"?
If so, store in a JS-labelled array; otherwise, use a CSS-labelled array.
Check if a class was specified; if it wasn't, use this class.
If we have a boolean value for the given class in the labelled array, it's not the first time.
Otherwise, set the boolean value for the given class to true.
I know what you're thinking: This makes no sense, it doesn't even store the calling function's name! And you'd be right; this method is not extensible, and has a huge overhead.
If you want to do what this method does, just use a static variable in the class in question to keep track of whether or not functions have been called. Your colleague's method—sorry to say—is inefficient and ineffective.
Take A hidden input field and
<input type="hidden" id="start_function_count" value="0">
and then call a function
<li onclick="myFunction('start_function_count')">
js function
MyFunction(count_id) {
var function_count = $("#"+count_id).val();
if(function_count == 0){
// CODE HERE for 1st time function call
// SET HIDDEN FIELD
$("#"+count_id).val(1);
} else{
// SECOnd time code;
}
}
just use a static field in the function. This static field will only be initialized once and not overwritten on new function calls.
If you use this in class methods, do take care that each inherited child class will have it's own version. So a static function field updated in ParentClass won't update the static function field in ChildClass extends ParentClass.
See it in action https://ideone.com/iR7J5O
function beDifferentFirstTime()
{
static $firstTime = true;
if($firstTime) {
$firstTime = false;
echo "I will say this only once, so listen carefully\n";
}
echo "The cabbage is in the cart. I repeat, the cabbage is in the cart.\n";
}
beDifferentFirstTime();
beDifferentFirstTime();

Avoid error 'Parameter $arg could not be found in method()' on variable arguments methods on phpDocumetor

I've been recently documenting my classes, and one of them has a method with no arguments in its definition, but because I parse them with get_func_args(). Let me show you:
public function method()
{
if(func_num_args() == 2)
{
//...
}
}
The problem's that when I document it, I want to add which arguments it receives. Something like this:
/**
* Some info
* #param string $arg Some value
* #param mixed $arg2 Some value
*/
Before asking, I do this with the get_func_args() stuff because it extends an abstract class, whose arguments differ a little from each implementation.
When I document this class, it pops a notice:
Parameter $arg could not be found in method()
Any way to avoid this, or to tell phpDocumentor that this class has in fact some parameters?
I think you'll have to review your architecture and match arguments in abstract and children classes, because PHPDoc seems to be strict about parameters given in annotations.

so how does passing by reference in php REALLY work?

Really simple question but rather than asking for an academic explanation I want to keep it as pragmatic as possible: when will PHP create a copy of my huge class I'm passing into a function and when will it simply create a pointer to the relevant data? And if it creates pointers all the time, what's the use of specifying & (aside from closures, obviously)? I guess I don't know enough about the guts of the interpreter.
In PHP 5, all objects are passed by their handle. Whether you pass by reference or not is irrelevant in terms of performance. (In fact, passing by reference is warned to be slower in the manual.) The object you are working on inside the function is the same object as pointed to outside the function.
When you pass an object (handle) by reference, then you can alter what the outer variable points to. This is almost always unnecessary.
The & operator denotes a variable as being passed by reference.
$x = 'Hello World';
echo($x);
function asdf(&$var){
$var = 'Test';
}
asdf($x);
echo($x);
Same goes for assignment and pretty much any other statement. If it isn't passed or assigned by reference, assume it is passed or assigned by value instead.
Why bother with &, even though you can do so as please. This is how I do:
Assume I have a class 'Book' with some public methods and properties like title, author, year
then to make an object of it simply:
$book = new Book()
// then I can use all public methods and properties
$book->title;
$book->author;
$book->year;
If I like to then I can make a subclass say
class Novel extends Books{
function buildIt(Book $bk){
$bk->title;
// so on
}
}
In the function buildIt, I purposedly have an class object of Book 'parameter' in which
I can pass the whole object of class 'Book'.
I hope this help.
You can find a lot of uses of passing a variable by reference in the PHP manual. One of the best examples is preg_match.
preg_match will return the number of occurrences a pattern has been matched in the input string. It will then populate, if provided, a referenced $matches array containing the matches.
It can be seen as a way to return more than one value, although you ought to be careful with that. Per example:
class Server {
protected $_clientId = 0;
protected $_clients = array();
/**
* Get a pending connection.
*
* #param &$connection_id int The connection identifier.
* #return resource The socket resource.
*/
public function getNextClient(&$connection_id) {
$clientSocket = socket_accept($this->_server);
$connection_id = $this->_clientId++;
$this->_clients[$connection_id] = $clientSocket;
return $clientSocket;
}
}
$server = new Server;
$socket1 = $server->getNextClient($id);
echo $id; // 0
$socket2 = $server->getNextClient($id);
echo $id; // 1
Important note. Objects are passed-by-reference by default. They will not be cloned. Even without specifying the & in the function argument, modifying the passed object will result in the original object being modified as well. The only way to prevent this is to clone the object in the function/method.

Load functions dynamically into class from external file

Is it possible in php to load a function, say from a external file to include in a class.
I'm trying to create a loader for helper functions so that I could call:
$registry->helper->load('external_helper_function_file');
after that it should be able call the function in file like this:
$registry->helper->function();
Thanks for any help
Setting aside opinions it it's good OOP design. It's possible even with current version of PHP, although not as clean, as it can be with PHP5.3.
class Helper {
/* ... */
function load($file) {
include_once($file);
}
function __call($functionName, $args) {
if(function_exists($functionName))
return call_user_func_array($functionName, $args);
}
}
ok, 1st, i agree that this is bad manners. also, in 5.3, you could use the new closure syntax with the __call magic word to use operators as functions (JS style).
now, if we want to supply a way of doing this you way, i can think of using create_fnuction, mixed with the __call magic.
basically, you use a regex pattern to get convert the functions into compatible strings, and put themin a private member. than you use the __call method to fetch them. i'm working on a small demo.
ok, here is the class. i got the inspiration from a class i saw a few weeks ago that used closures to implement JS-style objects:
/**
* supplies an interface with which you can load external functions into an existing object
*
* the functions supplied to this class will recive the classes referance as a first argument, and as
* a second argument they will recive an array of supplied arguments.
*
* #author arieh glazer <arieh.glazer#gmail.com>
* #license MIT like
*/
class Function_Loader{
/**
* #param array holder of genarated functions
* #access protected
*/
protected $_funcs = array();
/**
* loads functions for an external file into the object
*
* a note- the file must not contain php tags.
*
* #param string $source a file's loaction
*
* #access public
*/
public function load($source){
$ptrn = '/function[\s]+([a-zA-Z0-9_-]*)[\s]*\((.*)\)[\s]*{([\w\s\D]+)}[\s]*/iU';
$source = file_get_contents($source);
preg_match_all($ptrn,$source,$matches);
$names = $matches[1];
$vars = $matches[2];
$funcs = $matches[3];
for ($i=0,$l=count($names);$i<$l;$i++){
$this->_funcs[$names[$i]] = create_function($vars[$i],$funcs[$i]);
}
}
public function __call($name,$args){
if (isset($this->_funcs[$name])) $this->_funcs[$name]($this,$args);
else throw new Exception("No Such Method $name");
}
}
limitations- 1st, the source cannot have any php tags. 2nd, functions will always be public. 3rd- we can only mimic $this. what i did was to pass as a 1st argument $this, and the second is the array of arguments (which is a 4th limition). also, you will not be able to access non-public members and methods from within the class.
an example for a source file:
function a($self,$arr=array()){
//assuming the object has a member called str
echo $self->str;
}
this was a fun exercise for me, but a bad practice all in all
So you want to not just include a file, but include it into an object's scope?
...
I think you're going about this the wrong way. It makes more sense if the registry object has a series of helper members, which have functions of their own. The net result might look something like this:
$registry->aHelper->aFunction();
$registry->aDifferentHelper->aDifferentFunction();
With careful use of {} syntax, you should be able to dynamically add member objects to your god object.
At this point it's worth noting that a god object is almost invariable an anti-pattern. If you need those functions globally, use a bootstrapping include technique and put then in global scope. If you need to pass that data around, then either pass it to functions as required or store it in a database and retrieve it elsewhere.
I know that god object really looks like a good idea, but I promise you it will make things a mess later on.

Categories