Convert a string to function (callable) and keep it cached - php

I'm trying to make a little benchmarking script where I can enter short pieces of code for quick evaluation of my anticipations. I imagine it similar to jsPerf (but password-protected for security reasons).
The main loop should look like this:
public function run(&$t, $count) {
//Run setup function
if(is_callable($this->setup))
call_user_func($this->setup);
//Save inital time
$t($this->name);
//THE MAIN LOOP
for($i=0; $i<$count; $i++) {
call_user_func($this->fn);
}
//Save end time
$t($this->name."_end");
//return time difference
return $t[$this->name."-".$this->name."_end"];
}
However, this will only work with static approach - with functions defined while making the script:
//New instance of tester
$b = new Benchmarker();
$b->add(
//Name
"touch",
//closure
function() {
touch("file.txt");
},
//Code seen in final reports
"touch()"
);
So as you see, I use call_user_func, not eval. Besides the fact that it's evil function in it's nature, I want to avoid it for performance reasons. If I'm testing a code that takes about 10ns to process and eviluation takes about 100ns, my results will be rather random.
This is why I'm looking for a way to convert string to a callable object. You can think about it like one-time eval.
$callable = string_to_callable("function() {echo \"Hello world!\";}");
$b->add(
//Name
"echo",
//callable object
$callable,
//Code seen in final reports
"echo \"...\""
);
Is that possible?
Note:
I can see funny workaround using include:
//Code received from the user
$code = "echo \"Hello world!\";";
//Random name for a new function
$rndname = "fn_".rand(0,100000); //There are smarter ways to do this of course
//String of the new function
$func = "function $rndname() {{$code}}";
//Define a filename
$f = $rndname.".php";
//Put the code in the file
file_put_contents($f, "<?php\n$func\n?".">");
//Include the new script
include $f;
//Call the function
call_user_func($rndname);
//Delete the file
unlink($f);
I really do hope that I won't need the code above!

Apart from creating a new file, there may be a closure trick:
function string_to_callable($string) {
return eval("return function() {{$string}};");
}

Related

Effective form processing using php

I'm working on some project and I want to process requests from forms in several templates. The question is how is to invoke a proper function in the handling scrip. Although, I've been coding for a while, I still cant come up with anything better then using a variable in a hidden field:
if ($_POST['somehiddenfield'] == 1) {
some_function_1();//doesnt matter if its a function or a method
}
if ($_POST['somehiddenfield'] == 2) {
$mainclass->somemethod();
}
//goes on indefinitely
Also I want to keep everything in a single handler file, where my main class is invoked. So is there a more effective way than using if ... else?
I'd do the following:
still have a hidden field, but let it contain something like the form name
<input type="hidden" name="formName" value="post">
Then you can do something like that in the consuming php script:
<?php
// whatever class you use... this is just a simple dummy
class FormsProcessor {
public function post($params) {
echo "processing post form";
}
}
$formName = "post"; // would be $formName = filter_input(INPUT_POST, $_POST['formName'],FILTER_SANITIZE_STRING,FILTER_FLAG_STRIP_HIGH);
// BUT BE SURE TO SANITIZE THE INPUT!!!
$params = []; // dummy
$formsProcessor = new FormsProcessor();
// here's the trick.
$formsProcessor->{$formName}($params);
// to be even safer you could check first if this method_exists()
// and/or if it's in a list of allowed methods.
Be aware that there mustn't be any other methods in this class that the user shouldn't invoke. You could go around that by really compose the method name of two parts:
$methodName = $formName."Processor";
//....
$formsProcessor->{$methodName}();`
I would keep a key=>value array hardcoded with all the possible options. Pass the hidden input field, check if there are any intersections between your post values and the keys of the hardcoded options and call any matching values as functions.
$map = [
'yourHiddenField' => 'myFunctionName',
'anotherHiddenField' => 'myOtherFunctionName',
'yourOtherHiddenField' => 'yetAnotherfunctionName',
];
$intersection = array_intersect(array_keys($map), array_keys($_POST));
foreach ($intersection as $key) {
$this->{$map[$key])();
}
This code hasn't been tested.
EDIT:
Be careful with allowing ANY input to be ran without predefining which functions you should allow to be ran.
Example of how dangerous it could be even with sanitisation:
class Test {
public $i = 1;
function __construct(){
$this->i++;
}
}
$formVariable = '__construct';
$t = new Test();
$t->{$formVariable}();
echo $t->i;

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.

Calling a single function from another file without including the whole file in php

Is it possible to call only the specific function from another file without including whole file???
There may be another functions in the file and don't need to render other function.
The short answer is: no, you can't.
The long answers is: yes, if you use OOP.
Split your functions into different files. Say you are making a game with a hero:
Walk.php
function walk($distance,speed){
//walk code
}
Die.php
function die(){
//game over
}
Hero.php
include 'Walk.php';
include 'Die.php';
class Hero(){
//hero that can walk & can die
}
You may have other functions like makeWorld() that hero.php doesn't need, so you don't need to include it. This question has been asked a few times before: here & here.
One of the possible methods outlined before is through autoloading, which basically saves you from having to write a long list of includes at the top of each file.
In PHP it's not available to get only a little part of a file.
Maybe this is a ability to use only little parts of a file:
I have a class that calls "utilities". This I am using in my projects.
In my index.php
include("class.utilities.php")
$utilities = new utilities();
The file class.utilities.php
class utilities {
function __construct() {
}
public function thisIsTheFunction($a,$b)
{
$c = $a + $b;
return $c;
}
}
And then i can use the function
echo $utilities->thisIsTheFunction(3,4);
include a page lets say the function is GetPage and the variable is ID
<?php
require('page.php');
$id = ($_GET['id']);
if($id != '') {
getpage($id);
}
?>
now when you make the function
<?php
function getpage($id){
if ($id = ''){
//// Do something
}
else {
}
}
?>

How do I verify that this function is a string in PHPUnit?

Here's the code for my original PHP code:
public function outputText() {
$i = 1;
foreach($this->sorted_data as $this->data) {
echo "$i. ".$this->data[0]."<br/>";
$i++;
}
}
And here's the code for the PHPUnit:
public function testVerify() {
$yn = new SortThisData();
$yn->readFile("input.txt");
$output = $yn->outputText();
$this->assertTrue(is_string($output));
//if(!is_string($yn->get()))
// return false;
//$this->assertNotEmpty($yn->get());
}
The class is called SortThisData in the original PHP file.
When I used gettype(), it said it was null. I'm trying to verify that it is a string so it can pass in PHPUnit. Is there a way I can do this?
You're looking for assertInternalType().
Update: I didn't realize you were echoing the output. You will probably need to use output buffering to capture the text.
public function testVerify() {
$yn = new SortThisData();
$yn->readFile("input.txt");
// start output buffering and capture the output
ob_start();
$yn->outputText();
$output = ob_get_clean();
$this->assertInternalType('string', $output);
}
No disagreement with Baylor's answer. To answer the question, as asked, what you had was also good enough:
$this->assertTrue(is_string($output));
Or you could have done:
$this->assertEquals('string',gettype($output));
(The advantage of the latter is, when it fails, it will also tell you the type of $output; assertTrue will only tell you that something failed.)
assertInternalType() does exactly that, but was only introduced in PHPUnit 3.5, and you will still find PHPUnit 3.4 in use on some machines.

Optimize file include inside functions in PHP

I have a function that needs to include a file, however this functions is used in a place from 200 to 300 times, this is obviously causing efficiency issues, is there a way to optimize this inside the function? (i know there are many ways in which i can fix this but it will cause too much impact in the whole application)
I will just put a little example, this is not the whole function.
function getString(arrayName, strValue){
inclue('stringArrays.php');
return $$arrayName[strValue];
}
I tried using include_once, but that doesn't do the job either.
Thanks in advance.
You could use a static variable in the function to hold your values:
function getString($arrayName, $strValue){
static $string_arrays = array();
if (empty($string_arrays)) {
include('stringArrays.php');
$string_arrays = array_diff_key(get_defined_vars(), array(
'string_arrays' => true,
'arrayName' => true,
'strValue' => true,
));
}
return $string_arrays[$arrayName][$strValue];
}
Should only include the file once.
You could always add another parameter, perhaps a boolean, to tell the function whether or not to include it.
function getString(arrayName, strValue, includeFile)
{
if (includeFile)
{
inclue('stringArrays.php');
}
return $$arrayName[strValue];
}
You can try globalizing what's in stringArrays.php so you can check to see if that global variable is already set before including the file. Hard to tell without seeing what structure is in stringArrays.php.
If your function does nothing more than include a file you should be first evaluating whether that function should be called in the first place or make the function determine if an include is required. Basically don't blindly include a file if you truly don't need it included. include_once will incur a performance hit.
Install APC, eAccelerator, XCache or any other code accelerator so PHP doesn't need to retrieve the include file from disk every time it's called. Code accelerators save the file in shared memory. That will improve performance significantly.
Is there anything preventing you from wrapping your current "bunch" of arrays in an array, then passing that wrapper array into the function by reference? You can then do a single require/include outside of the function. Alternatively, you can wrap both the set of arrays and the function inside an object, again bringing you down to a single require/include.
If stringArrays.php is simply a collection of arrays, what about creating a stringHandler singleton that includes stringArrays.php within the constructor and maps the each array to a class property, then a simple method to get whichever you want from that class. Then your getString() function simply references a getter method in the stringHandler.
stringArrays.php
<?php
$abc = array('def' => 'Hello',
'ghi' => ' '
);
$jkl = array('mno' => 'World',
'pqr' => '.'
);
?>
stringHandler.php
<?php
class stringHandler
{
private static $instance;
private function __construct()
{
include('stringArrays.php');
foreach(get_defined_vars() as $key => $val) {
$this->{$key} = $val;
}
}
public static function singleton()
{
if (!isset(self::$instance)) {
$c = __CLASS__;
self::$instance = new $c;
}
return self::$instance;
}
public function getStringFromArray($arrayName, $strValue)
{
return $this->{$arrayName}[$strValue];
}
}
function getString($arrayName, $strValue){
return stringHandler::singleton()->getStringFromArray($arrayName, $strValue);
}
echo getString('abc','def');
echo getString('abc','ghi');
echo getString('jkl','mno');
?>
Kludgy, but shouldn't be a big performance overhead.

Categories