Can temporary functions/macros be created in PHP? - php

Take a look at the following illustration:
// Trims input, fixes spaces and encodes bad glyphs. Also works with arrays.
function prepare_param($param)
{
$retval = "";
function prc($param)
{
$r = split(" ", trim($param));
foreach($r as $i => $e)
$r[$i] = urlencode($e);
return join("+", $r);
}
// If input is an array
if(is_array($param))
{
$retval = array();
foreach($param as $e)
$retval[] = prc($e);
}
// If input is a string
else if(is_string($param))
{
return prc($param);
}
else throw new Exception("Invalid input! Expected String or Array.");
}
Obviously the function prc will now be declared globally, even though declared inside a function. Is there a way to follow this principle, creating a tiny function/macro inside another function as not to litter the global scope? The alternative would be to make a class with a private function, which seems like overkill for my use.
Any help appreciated

You probably want closures, which are anonymous functions.

If you have PHP 5.3, enter anonymous functions:
$prc = function($param)
{
$r = split(" ", trim($param));
foreach($r as $i => $e)
$r[$i] = urlencode($e);
return join("+", $r);
};
if(is_array($param))
{
$retval = array();
foreach($param as $e)
$retval[] = $prc($e);
}
else if(is_string($param))
{
return $prc($param);
}
In this case, $prc only lives in the scope of your prepare_param() function.

If you have access to >=PHP 5.3, you can use anonymous functions, and if not, you can use create_function.

If you don't have PHP 5.3, you can use the create_function function.

There are two ways to do so. The closures/anonymous functions are possible from PHP 5.3, and the oldschool way would be to use create_function() - which is quite fugly.
However in your case, you don't want either. There is no benefit in creating or recreating the function. You just need it once, as it does not depend on any initialization state. The idiom you should use is called "dererred definition" and possible in PHP with:
if (!function_exists("prc")) {
function prc($param) {
...
}
}
You should name it with its parent function as prefix however (e.g. prepare__prc) to avoid clashes and to signalize its internal use.
Oh, and btw it could also be simplified compacted into:
$param = join("+", array_map("urlencode", split(" ", trim($param))));

anonymous functions might be what you are looking for
<?php
$greet = function($name)
{
printf("Hello %s\r\n", $name);
};
$greet('World');
$greet('PHP');
?>
If you don't use php 5.3 please be aware of the fact that the memory allocated by the "create_function()" function isn't released until the php process finishes. So if you create a lot of functions you might be running into issues.

Related

PHP Magic Method for assignment operator

I'm trying to create a class that enforces its type much like the PHP SplString class.
In this class you can create a string (example from php.net)
$string = new SplString("Testing");
try {
$string = array();
} catch (UnexpectedValueException $uve) {
echo $uve->getMessage() . PHP_EOL;
}
var_dump($string);
echo $string; // Outputs "Testing"
I know PHP is loosely typed however they have got this functionality in SplTypes so I was hoping there might be some way of mimicking this behavior.
I would be expecting to implement it in this kind of fashion below.
public function __assign($value)
{
if($value instanceof MyClass)
{
return true;
}
return false;
}
I'd like to be able to introduce this behavior in my own classes, but cant find the relevant magic method for assignments.
Is this even possible? Or is this a language feature that can't be controlled?

Multiple functions of the same name

I am looking to create an extension api for my web application.
Example extension file:
function echoCustomHeaders(){
echo '<li>Header Link</li>';
}
There would be several files similar to the example extension file (with the same function name, for user friendlyness when programming addons).
for($x=0;$x<count($extension_files);$x++){
//This would obviosely break when it gets to the second file, as functions cannot be declared twice in php
require_once($extension_files[$x]);
}
//some code later...
//this should call echoCustomHeaders() in ALL of the extension files, what code should I put here to make this happen?
echoCustomHeaders();
In case you are wondering about what the question is, read the comments in the code above and it should be fairly easy to see.
Return closures (lambda expressions) in your extension files as follows:
return function(){
echo '<li>Header Link</li>';
}
In PHP the include/require statement is really a function and therefore has a return value, hence you can collect those closures into an array:
$closures = array();
for($x=0;$x<count($extension_files);$x++){
$closures[$i]=include($extension_files[$x]);
}
// Do whatever you want with your closures, e.g. execute them:
foreach($closures as $closure) {
$closure();
}
ADDED CONTENT:
In the case if you would like to return multiple closures with each include, you may return an array of closures, indexed by the name of them:
return array(
'echoCustomHeaders' => function() {
echo '<li>Header Link</li>';
},
// ...
);
Then you can still execute some of them by their name:
$closureArray = array();
foreach($extension_files as $file) {
$closureArray[] = include($file);
}
foreach($closureArray as $closure) {
if(isset($closure['echoCustomHeaders'])) // Maybe there wasn't an echoCustomHeaders in each extension file ...
$closure['echoCustomHeaders']();
}
Maybe it would be a better idea to even separate the different kind of extension functions into distinct arrays:
$closureArray = array();
foreach($extension_files as $file) {
$functions = include($file);
foreach($functions as $name => $function) {
if(!isset($closureArray[$name]))
$closureArray[$name] = array();
$closureArray[$name][] = $function;
}
}
foreach($closureArray['echoCustomHeaders'] as $closure) {
$closure();
}
Another solution is to use a more object oriented way, and declare a new extension class in each extension file. However, if there would be no data sharing required between the extension methods in an extension file, then simply returning the functions as an array of closures is a more lightweight and cleaner solution in my opinion.
1.maybe you can use the new feature after php5.3:namespace http://www.php.net/manual/en/language.namespaces.php, then you can use the same name functions.
2.however you could think about the object oriented solution,for example,defined a base class who has a method echoCustomHeaders.

overloading PHP functions to perform an action first

I was wondering how I could overload a standard function in php. Specifically, I'm trying to implement security checks on certain functions. As such, I would like to redefine write as:
function fwrite($handle, $string, $length = null) {
if (doMyChecks()) {
original_fWrite($handle, $string, $length);
} else {
recordViolation();
}
}
I'm using CodeIgniter, so I would put this code in index.php to make it applicable for all pages called through the framework.
It seems that you could use the PHP function override_function(). From the PHP.net site:
override_function('test', '$a,$b', 'echo "DOING TEST"; return $a * $b;');

How to alias a function in PHP?

Is it possible to alias a function with a different name in PHP? Suppose we have a function with the name sleep. Is there a way to make an alias called wait?
By now I'm doing like this:
function wait( $seconds ) {
sleep($seconds);
}
Until PHP 5.5
yup, function wait ($seconds) { sleep($seconds); } is the way to go. But if you are worried about having to change wait() should you change the number of parameters for sleep() then you might want to do the following instead:
function wait() {
return call_user_func_array("sleep", func_get_args());
}
PHP 5.6+ only
Starting with PHP 5.6 it is possible to alias a function by importing it:
use function sleep as wait;
There's also an example in the documentation (see "aliasing a function").
Nope, but you can do this:
$wait = 'sleep';
$wait($seconds);
This way you also resolve arguments-number-issues
You can look at lambdas also if you have PHP 5.3
$wait = function($v) { return sleep($v); };
If you aren't concerned with using PHP's "eval" instruction (which a lot of folks have a real problem with, but I do not), then you can use something like this:
function func_alias($target, $original) {
eval("function $target() { \$args = func_get_args(); return call_user_func_array('$original', \$args); }");
}
I used it in some simple tests, and it seemed to work fairly well. Here is an example:
function hello($recipient) {
echo "Hello, $recipient\n";
}
function helloMars() {
hello('Mars');
}
func_alias('greeting', 'hello');
func_alias('greetingMars', 'helloMars');
greeting('World');
greetingMars();
No, there's no quick way to do this in PHP. The language does not offer the ability to alias functions without writing a wrapper function.
If you really really really needed this, you could write a PHP extension that would do this for you. However, to use the extension you'd need to compile your extension and configure PHP to us this extension, which means the portability of your application would be greatly reduced.
No, functions aren't 1st-class citizens so there's no wait = sleep like Javascript for example. You basically have to do what you put in your question:
function wait ($seconds) { sleep($seconds); }
you can use runkit extension
http://us.php.net/manual/en/function.runkit-function-copy.php
function alias($function)
{
return function (/* *args */) use ($function){
return call_user_func_array( $function, func_get_args() );
};
}
$uppercase = alias('strtoupper');
$wait = alias('sleep');
echo $uppercase('hello!'); // -> 'HELLO!'
$wait(1); // -> …
If your PHP doesn't support use x as y syntax, in older PHP version you can define anonymous function:
$wait = create_function('$seconds', 'sleep($seconds);');
$wait(1);
Or place the code inside the constant, e.g.:
define('wait', 'sleep(1);');
eval(wait);
See also: What can I use instead of eval()?
This is especially useful if you've long piece of code, and you don't want to repeat it or the code is not useful for a new function either.
There is also function posted by Dave H which is very useful for creating an alias of a user function:
function create_function_alias($function_name, $alias_name)
{
if(function_exists($alias_name))
return false;
$rf = new ReflectionFunction($function_name);
$fproto = $alias_name.'(';
$fcall = $function_name.'(';
$need_comma = false;
foreach($rf->getParameters() as $param)
{
if($need_comma)
{
$fproto .= ',';
$fcall .= ',';
}
$fproto .= '$'.$param->getName();
$fcall .= '$'.$param->getName();
if($param->isOptional() && $param->isDefaultValueAvailable())
{
$val = $param->getDefaultValue();
if(is_string($val))
$val = "'$val'";
$fproto .= ' = '.$val;
}
$need_comma = true;
}
$fproto .= ')';
$fcall .= ')';
$f = "function $fproto".PHP_EOL;
$f .= '{return '.$fcall.';}';
eval($f);
return true;
}
nope. the way you wrote is the best way to do it.
No, there's no quick way to do so - at least for anything before PHP v5.3, and it's not a particularly good idea to do so either. It simply complicates matters.
Since PHP 5.6
This is especially helpful for use in classes with magic methods.
class User extends SomethingWithMagicMethods {
public function Listings(...$args) {
return $this->Children(...$args);
}
}
But I'm pretty sure it works with regular functions too.
function UserListings(...$args) {
return UserChildren(...$args);
}
Source:
PHP: New features -> "Variadic functions via ..."
I know this is old, but you can always
$wait = 'sleep';
$wait();
What I have used in my CLASS
function __call($name, $args) {
$alias['execute']=array('done','finish');
$alias['query']=array('prepare','do');
if (in_array($name,$alias['execute'])){
call_user_func_array("execute",$args);
return TRUE;
}elseif(in_array($name,$alias['query'])){
call_user_func_array("query",$args);
return TRUE;
}
die($this->_errors.' Invalid method:'.$name.PHP_EOL);
}

How do I implement a callback in PHP?

How are callbacks written in PHP?
The manual uses the terms "callback" and "callable" interchangeably, however, "callback" traditionally refers to a string or array value that acts like a function pointer, referencing a function or class method for future invocation. This has allowed some elements of functional programming since PHP 4. The flavors are:
$cb1 = 'someGlobalFunction';
$cb2 = ['ClassName', 'someStaticMethod'];
$cb3 = [$object, 'somePublicMethod'];
// this syntax is callable since PHP 5.2.3 but a string containing it
// cannot be called directly
$cb2 = 'ClassName::someStaticMethod';
$cb2(); // fatal error
// legacy syntax for PHP 4
$cb3 = array(&$object, 'somePublicMethod');
This is a safe way to use callable values in general:
if (is_callable($cb2)) {
// Autoloading will be invoked to load the class "ClassName" if it's not
// yet defined, and PHP will check that the class has a method
// "someStaticMethod". Note that is_callable() will NOT verify that the
// method can safely be executed in static context.
$returnValue = call_user_func($cb2, $arg1, $arg2);
}
Modern PHP versions allow the first three formats above to be invoked directly as $cb(). call_user_func and call_user_func_array support all the above.
See: http://php.net/manual/en/language.types.callable.php
Notes/Caveats:
If the function/class is namespaced, the string must contain the fully-qualified name. E.g. ['Vendor\Package\Foo', 'method']
call_user_func does not support passing non-objects by reference, so you can either use call_user_func_array or, in later PHP versions, save the callback to a var and use the direct syntax: $cb();
Objects with an __invoke() method (including anonymous functions) fall under the category "callable" and can be used the same way, but I personally don't associate these with the legacy "callback" term.
The legacy create_function() creates a global function and returns its name. It's a wrapper for eval() and anonymous functions should be used instead.
With PHP 5.3, you can now do this:
function doIt($callback) { $callback(); }
doIt(function() {
// this will be done
});
Finally a nice way to do it. A great addition to PHP, because callbacks are awesome.
Implementation of a callback is done like so
// This function uses a callback function.
function doIt($callback)
{
$data = "this is my data";
$callback($data);
}
// This is a sample callback function for doIt().
function myCallback($data)
{
print 'Data is: ' . $data . "\n";
}
// Call doIt() and pass our sample callback function's name.
doIt('myCallback');
Displays: Data is: this is my data
One nifty trick that I've recently found is to use PHP's create_function() to create an anonymous/lambda function for one-shot use. It's useful for PHP functions like array_map(), preg_replace_callback(), or usort() that use callbacks for custom processing. It looks pretty much like it does an eval() under the covers, but it's still a nice functional-style way to use PHP.
well... with 5.3 on the horizon, all will be better, because with 5.3, we'll get closures and with them anonymous functions
http://wiki.php.net/rfc/closures
You will want to verify whatever your calling is valid. For example, in the case of a specific function, you will want to check and see if the function exists:
function doIt($callback) {
if(function_exists($callback)) {
$callback();
} else {
// some error handling
}
}
create_function did not work for me inside a class. I had to use call_user_func.
<?php
class Dispatcher {
//Added explicit callback declaration.
var $callback;
public function Dispatcher( $callback ){
$this->callback = $callback;
}
public function asynchronous_method(){
//do asynch stuff, like fwrite...then, fire callback.
if ( isset( $this->callback ) ) {
if (function_exists( $this->callback )) call_user_func( $this->callback, "File done!" );
}
}
}
Then, to use:
<?php
include_once('Dispatcher.php');
$d = new Dispatcher( 'do_callback' );
$d->asynchronous_method();
function do_callback( $data ){
print 'Data is: ' . $data . "\n";
}
?>
[Edit]
Added a missing parenthesis.
Also, added the callback declaration, I prefer it that way.
For those who don't care about breaking compatibility with PHP < 5.4, I'd suggest using type hinting to make a cleaner implementation.
function call_with_hello_and_append_world( callable $callback )
{
// No need to check $closure because of the type hint
return $callback( "hello" )."world";
}
function append_space( $string )
{
return $string." ";
}
$output1 = call_with_hello_and_append_world( function( $string ) { return $string." "; } );
var_dump( $output1 ); // string(11) "hello world"
$output2 = call_with_hello_and_append_world( "append_space" );
var_dump( $output2 ); // string(11) "hello world"
$old_lambda = create_function( '$string', 'return $string." ";' );
$output3 = call_with_hello_and_append_world( $old_lambda );
var_dump( $output3 ); // string(11) "hello world"
I cringe every time I use create_function() in php.
Parameters are a coma separated string, the whole function body in a string... Argh... I think they could not have made it uglier even if they tried.
Unfortunately, it is the only choice when creating a named function is not worth the trouble.

Categories