Is there a trick in PHP 4 to implement functions which return functions? I expected that the following code would work:
function xxx($a) {
return function($b) {
print "a=$a, b=$b \n";
}
}
$f1 = xxx(1);
$f1(2);
Unfortunately, no luck in PHP 4. Probably it works in PHP 5, but I limited to PHP 4.
I tried to workaround with OO, but again failed (class declarations may not be nested):
class Closure {
function run($a) {
print "raise: NotImplementedException, instead: $a\n";
}
}
class WantCheckNesting extends Closure {
function run($a, $b) {
class Nested extends Closure {
function run($c) {
print "a=$a, b=$b, c=$c\n";
}
}
$o = new Nested();
return $o;
}
}
$d = new WantCheckNesting();
$e = $d->run(2, 3);
$e->run(4);
There is a function "create_function", but it is very limited: the body must be a string.
Any other ideas?
You're probably barking at the wrong tree. PHP is not a functional programming language. Some changes have been made starting with PHP 5.3, but even there you don't have your expected variable scopes that would allow you to do what you have in your examples.
The only tools you can use in PHP 4 are create_function and some ingenuity to write the function definition as a string.
<?php
function getMyFunc($a){
return create_function('$b', 'print "a='.$a.', b=$b";');
}
$f1 = getMyFunc(1);
$f1(2);
?>
...but even if this is simple for your posted example, it definitely isn't practical for more complex situations.
In PHP4 you can use Variable Functions like this, provided your function is already defined in the scope (so not a real closure).
THIS IS DIRTY CODE.
THIS IS NOT MUCH TESTED.
THIS IS NOT FAST (even slower than closures if that is possible).
It is just for fun and proving it "somehow" can be done if you really really need it.
Requires a writable tmp/ directory.
<?php
function xxx($a) {
$sid = GetUniversalSessionId();
$tmpfname= 'tmp/'.$sid.'.php';
$handle = fopen($tmpfname, "w");
fwrite($handle, '<?php
function func_'.($sid).'($b) {
$a='."'".str_replace("\'","\\'",str_replace("\\","\\\\",$a))."'".';
print "a=$a, b=$b \n";
}
?>');
fclose($handle);
include($tmpfname);
unlink($tmpfname);
return 'func_'.($sid);
}
$result=xxx(32);
$result(20);
// This is just to get a unique identifier for every connection and every function call:
// UNIVERSALSESSIONIDS v1.3
if(defined('UNIVERSALSESSIONIDS')) return;
define('UNIVERSALSESSIONIDS', TRUE);
function GetTimeStart() {
return strtotime('2006-07-10');
}
function GetUniversalSessionId() {
return GetCodedSid(letterNumBase(),16);
}
function GetCodedSid($baseChars,$Pad=0) {
$Zero=$baseChars{0};
list ($usec, $sec) = explode (' ', microtime());
$new_sid = ($sec-GetTimeStart()) . str_pad ((int)($usec * 100000000), 8, '0', STR_PAD_LEFT) . str_pad (rand (0, 9999), 4, '0', STR_PAD_LEFT);
$new_sid=ConvertDecToAnyStr($new_sid,$baseChars);
$new_sid=str_pad ($new_sid, $Pad, $Zero, STR_PAD_LEFT);
return $new_sid;
}
function divide($decstr,$decnum) {
$Start='';
$Result='';
$WRITE=FALSE;
do {
$Start.=substr($decstr,0,1);
$decstr=substr($decstr,1);
$DecStart=intval($Start);
$Rest=$DecStart%$decnum;
$PartDiv=($DecStart-$Rest)/$decnum;
if($PartDiv>0) $WRITE=TRUE;
if($WRITE) $Result.=$PartDiv;
$Start=$Rest;
} while ($decstr!='');
if($Result=='') $Result='0';
return array($Result,$Rest);
}
function bigBase() {
global $gSavedBigBase;
if(isset($gSavedBigBase)) return $gSavedBigBase;
$BigBase='';
for($i=33;$i<=128;$i++) $BigBase.=chr($i);
$gSavedBigBase=$BigBase;
return $BigBase;
}
function letterNumBase() {
global $gSavedBigBase2;
if(isset($gSavedBigBase2)) return $gSavedBigBase2;
$BigBase='';
for($i=ord('0');$i<=ord('1');$i++) $BigBase.=chr($i);
for($i=ord('A');$i<=ord('Z');$i++) $BigBase.=chr($i);
$BigBase.='_';
// for($i=ord('a');$i<=ord('z');$i++) $BigBase.=chr($i);
$gSavedBigBase2=$BigBase;
return $BigBase;
}
function ConvertDecToAny($decstr,$decbase) {
$Result=array();
do {
$Div=divide($decstr,$decbase);
$decstr=$Div[0];
$Rest=$Div[1];
$Result[]=$Rest;
} while($decstr!='0');
return $Result;
}
function ConvertDecToAnyStr($decstr,$baseChars='01') {
$decbase=strlen($baseChars);
$Result='';
do {
$Div=divide($decstr,$decbase);
$decstr=$Div[0];
$Rest=$Div[1];
$Result=$baseChars{$Rest}.$Result;
} while($decstr!='0');
return $Result;
}
?>
Related
im just learning php
Im trying to add a log with comments to my functions output.
Right now it looks like this:
//the function
function add1($x){
if($GLOBALS['logging'] === 'on'){ $log[] = 'Adding 1 to '.$x;};
$a = $x + 1;
if($GLOBALS['logging'] === 'on'){
$return[] = $a;
$return[] = $log;
return $return;
}else{ return $a; };
};
//calling the function
if($GLOBALS['logging'] === 'on'){
$return = add1($x);
$number = $return[0];
$log = $return[1];
}else{ $number = add1($x); };
Im kinda annoyed by the fact i need to retype this if statement.
So i made a seperate function for returning the function
which looks like this:
//function
function log_return($data = 'x', $log = 'x'){
if($GLOBALS['logging'] === 'on'){
if($data !== 'x') $return[] = $data;
if($log !== 'x') $return[] = $log;
return $return;
} return $data;
};//function end
And returning it with:
return $return = isset($log) ? log_return($data, $log) : log_return($data);
Now my quastion is: Is there a way to call a function with function..
like:
call_function(add1($x));
so i can return it either with log or without..
Given the answer https://stackoverflow.com/a/2700760/5387193 - this should work:
function add1($a)
{
// add1 code goes here
}
function call_function($name, $param)
{
$name($param);
}
call_function('add1', $x);
On a side note, your variable and function names aren't very intuitive. Perhaps you should study how to write good quality readable code. I recommend reading chapter 9 of Refactoring by Martin Fowler, it's quite good. You can find a PDF version on the web.
Another note, your return statement return $return = isset($log) ? log_return($data, $log) : log_return($data); has a unnecessary assignment to $return. The code should simply read
return isset($log) ? log_return($data, $log) : log_return($data);
Yes, it is possible. To simplify:
function first($x) {
return $x+1;
}
function second($y) {
return $y+1;
}
echo second(first(1)); // Returns 3, ie. 1+1+1
As gview said in his comment, don't use global variables. Argument lists exist for several reasons, included but not limited to making code easier to read, edit, and debug. The same goes for function and variable names.
Moreover, your code is very messy. It can be consolidated:
function addTo($currentValue, $valueToAdd, $logging = 0)
{
if ($logging) {
logWrite('addTo', "Adding $valueToAdd to $currentValue");
return $currentValue + $valueToAdd;
} else {
return $currentValue;
}
}
function logWrite($operation, $message)
{
$log = getLog(); // maybe it's a file, or DB record or something
// perform the write, depending on your implementation
}
$number = addTo($someStaringValue, $someOtherValue, 1);
All of this said, logging should not control program flow. In other words, whether something is logged by the system or not should have no bearing on what your code is trying to do. I really think you need to take a broader view of what you're trying to do and break it up into components.
At best, your code should tell a logger to log info, and the logger itself should determine if logging is actually turned on. If it is, the info is logged. If not, then the code that calls on the logger still works and goes about its business.
I would like to return a value from an asynchronous function in PHP ... I use icicle.io here, but I'm happy to use whatever, provided it does what I want to do! Anyway, this is some code below
<?php
require __DIR__ . '/vendor/autoload.php';
use Icicle\Coroutine\Coroutine;
use Icicle\Loop;
function getArray($int) {
yield array ($int, $int + 1, $int + 2);
}
function getArrays() {
$numbers = array (1, 4, 7);
$results = array();
foreach ($numbers as $number) {
array_push($results, (yield(getArray($number))));
}
yield call_user_func_array('array_merge', $results);
}
$coroutine = new Coroutine(getArrays());
$data = $coroutine->then(
function ($result) {
$data = print_r($result, true);
return "Result: {$data}\n";
},
function (Exception $e) {
echo "Error: {$e->getMessage()}\n";
}
)->done(function ($value) {
echo $value;
});
Loop\run();
What I'd really like to do is to put that last little bit in a function, so it looks more like this:
function sync() {
$coroutine = new Coroutine(getArrays());
$data = $coroutine->then(
function ($result) {
$data = print_r($result, true);
return "Result: {$data}\n";
},
function (Exception $e) {
echo "Error: {$e->getMessage()}\n";
}
)->done(function ($value) {
return $value;
});
Loop\run();
return /* the value */;
}
Then from my cool software, I can call sync() as if it's a synchronous function, blissfully unaware of the asynchronous shenanigans going on behind the scenes.
Has anyone done this, or have some suggestions as to how I might? At the moment the best I've come up with is (ab)using the output buffer & serialize()/unserialize() functions, but since I'm doing it all out of some desire to improve the performance, that seems rather backwards!!
You can synchronously wait for the resolution of an Awaitable (including a Coroutine) by using the wait() method. This method ticks the event loop until the coroutine is resolved. This means your sync() function can simply call this method on the coroutine object and return the result.
function sync() {
$coroutine = new Coroutine(getArrays());
return $coroutine->wait();
}
I'm using PHP 5.3, coming from JS and Python land, can't use call() because < PHP 5.4
So let's say I have a function generator, e.g. to log things in JS land:
function console($meth){
return function() use($meth) {
print "<script>console.".$meth.".apply(console,".json_encode(func_get_args()).")</script>";
};
}
I want to dynamically evaluate this, like:
console($meth)($thing1,$thing2);
BUT
//console('log')('hello'); //syntax error!
sad tears! however, this works.
$func = console('log');
$func('hello');
WHY IS THIS THE CASE? WHYWHYWHY?
Also, how can I force console('log') to evaluate without using eval or assigning to a variable?
This will work starting at PHP 5.3:
function console($a) {
return function($b, $c) {
echo $b, $c;
};
}
$f = console("a");
$f("b", "c");
If you need to chain the call, this will work for all PHP 5 versions:
class Foo {
public function call($b, $c) {
echo $b, $c;
}
}
function console($a) {
return new Foo();
}
$f = console("a")->call("b", "c");
I would suggest to start learning PHP in a recent version. The PHP developers have added a lot of cool things in 5.4 and subsequent versions.
another way of solving that would be as follows:
class App_Console {
private static $methods = array(
'log',
'info',
'warn',
'dir',
'time',
'timeEnd',
'trace',
'error',
'assert'
);
function __call($name,$args){
if(in_array($name,self::$methods)){
printf("<script>console.$name.apply(console,%s)</script>\n",json_encode($args));
}
}
}
I have a function L($key) that translates my strings.
Nothing fancy:
$_langs = include(__DIR__ . '/lang.php');
function L($key)
{
global $_langs;
if (array_key_exists($key, $_langs)) {
return $_langs[$key];
} else {
return $key;
}
}
When I need parametrized translation (with %s), I use this:
sprintf(L('myKey'), $var)
Is there some easy way to make it so I can use just L('myKey', $var)?
I thought of adding array $params=null as a formal parameter (It'd then take array as second argument), but how can I then expand it to individual arguments of sprintf()?
As usual, I've figured it out right after asking ^^
Here's my solution - if you can write it better, feel free to answer and I can accept it.
// i18n utility
$_langs = include(__DIR__ . '/lang.php');
function L($key)
{
global $_langs;
if (array_key_exists($key, $_langs)) {
$formats = array_slice(func_get_args(), 1);
$sprintf_args = array_merge([$_langs[$key]], $formats);
return call_user_func_array('sprintf', $sprintf_args);
} else {
return $key;
}
}
I'm sure there's a very easy explanation for this. What is the difference between this:
function barber($type){
echo "You wanted a $type haircut, no problem\n";
}
call_user_func('barber', "mushroom");
call_user_func('barber', "shave");
... and this (and what are the benefits?):
function barber($type){
echo "You wanted a $type haircut, no problem\n";
}
barber('mushroom');
barber('shave');
Always use the actual function name when you know it.
call_user_func is for calling functions whose name you don't know ahead of time but it is much less efficient since the program has to lookup the function at runtime.
Although you can call variable function names this way:
function printIt($str) { print($str); }
$funcname = 'printIt';
$funcname('Hello world!');
there are cases where you don't know how many arguments you're passing. Consider the following:
function someFunc() {
$args = func_get_args();
// do something
}
call_user_func_array('someFunc',array('one','two','three'));
It's also handy for calling static and object methods, respectively:
call_user_func(array('someClass','someFunc'),$arg);
call_user_func(array($myObj,'someFunc'),$arg);
the call_user_func option is there so you can do things like:
$dynamicFunctionName = "barber";
call_user_func($dynamicFunctionName, 'mushroom');
where the dynamicFunctionName string could be more exciting and generated at run-time. You shouldn't use call_user_func unless you have to, because it is slower.
With PHP 7 you can use the nicer variable-function syntax everywhere. It works with static/instance functions, and it can take an array of parameters. More info at https://trowski.com/2015/06/20/php-callable-paradox
$ret = $callable(...$params);
I imagine it is useful for calling a function that you don't know the name of in advance...
Something like:
switch($value):
{
case 7:
$func = 'run';
break;
default:
$func = 'stop';
break;
}
call_user_func($func, 'stuff');
There are no benefits to call it like that, the word user mean it is for multiple user, it is useful to create modification without editing in core engine.
it used by wordpress to call user function in plugins
<?php
/* main.php */
require("core.php");
require("my_plugin.php");
the_content(); // "Hello I live in Tasikmalaya"
...
<?php
/* core.php */
$listFunc = array();
$content = "Hello I live in ###";
function add_filter($fName, $funct)
{
global $listFunc;
$listFunc[$fName] = $funct;
}
function apply_filter($funct, $content)
{
global $listFunc;
foreach ($listFunc as $key => $value)
{
if ($key == $funct and is_callable($listFunc[$key]))
{
$content = call_user_func($listFunc[$key], $content);
}
}
echo $content;
}
function the_content()
{
global $content;
$content = apply_filter('the_content', $content);
echo $content;
}
....
<?php
/* my_plugin.php */
function changeMyLocation($content){
return str_replace('###', 'Tasikmalaya', $content);
}
add_filter('the_content', 'changeMyLocation');
in your first example you're using function name which is a string. it might come from outside or be determined on the fly. that is, you don't know what function will need to be run at the moment of the code creation.
When using namespaces, call_user_func() is the only way to run a function you don't know the name of beforehand, for example:
$function = '\Utilities\SearchTools::getCurrency';
call_user_func($function,'USA');
If all your functions were in the same namespace, then it wouldn't be such an issue, as you could use something like this:
$function = 'getCurrency';
$function('USA');
Edit:
Following #Jannis saying that I'm wrong I did a little more testing, and wasn't having much luck:
<?php
namespace Foo {
class Bar {
public static function getBar() {
return 'Bar';
}
}
echo "<h1>Bar: ".\Foo\Bar::getBar()."</h1>";
// outputs 'Bar: Bar'
$function = '\Foo\Bar::getBar';
echo "<h1>Bar: ".$function()."</h1>";
// outputs 'Fatal error: Call to undefined function \Foo\Bar::getBar()'
$function = '\Foo\Bar\getBar';
echo "<h1>Bar: ".$function()."</h1>";
// outputs 'Fatal error: Call to undefined function \foo\Bar\getBar()'
}
You can see the output results here: https://3v4l.org/iBERh it seems the second method works for PHP 7 onwards, but not PHP 5.6.