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

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.

Related

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

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}};");
}

Overriding var_dump globally?

I don't like the way var_dump prints out objects. I want to override it with this function:
function var_dump($object, $die = true) {
print '<pre>';
print_r($object);
if ($die) die();
}
I know how to override it in my application, but is there a way to override it globally for all sites on a PHP config level?
You can not do that currently (via "good way") in PHP. And more - you shouldn't.
var_dump() is doing right for what it's intended: plain output and nothing more. If you want to change that, then by definition you want some user-defined behavior. Therefore:
Create your own function. That is what you have now. User-defined functions are for user-defined behavior.
Or else, if you want to do it with var_dump() name by some reason, use namespace like:
namespace Utils;
function var_dump($var, $exit=true, $return=true)
{
$result = sprintf('<pre>%s</pre>', print_r($var, true));
if($exit)
{
echo $result;
exit;
}
if($return)
{
return $result;
}
echo $result;
}
so usage will look like:
$obj = new StdClass();
$str = \Utils\var_dump($obj, false);
//do domething with $str
echo $str; //or use second false
Worst case: runkit_function_redefine() Remember, this is evil. You should not do that because redefining goes against what is function and why it was defined. It is a global side-effect and you should avoid such behavior.
You can use the override_function: http://www.php.net/manual/en/function.override-function.php to replace the behavior of the var_dump function. If you want to include this piece of code in all of your sites, you can put this in your php.ini file:
php_value auto_prepend_file /path/to/file_where_you_override_function.php

How do you mock a virtual binary file so that exec() / system() / passthru() function output can be tested?

I have an interesting problem and have searched the internet, but haven't yet found an answer.
I work for a company that doesn't allow it's workers to utilize OOP, it is kind of ridiculous, but the working experience is valuable.
Consider the following function:
function get_setting_values_from_file( $parameter )
{
exec("/usr/var/binary --options $parameter", $output, $return);
$settings = file( $output[0] );
foreach( $settings as $setting ) {
if( strstr( $setting, "color") ) {
$setting = explode( ":", $setting );
return $setting[1];
}
}
return false;
}
I need to unit test a similar function. I am currently using phpUnit for my tests and the vfsStream libraries to mock the file system, but how do you mock the call to exec("/usr/var/binary --options $parameter", $output, $return) when I'm developing with no access to the actual system? What is the recommend approach for dealing with test cases like this?
All feedback is appreciated.
You could mock exec() by using a function mock library. I made one (php-mock) for you which requires you to use namespaces
namespace foo;
use phpmock\phpunit\PHPMock;
class ExecTest extends \PHPUnit_Framework_TestCase
{
use PHPMock;
public function testExec()
{
$mock = $this->getFunctionMock(__NAMESPACE__, "exec");
$mock->expects($this->once())->willReturnCallback(
function ($command, &$output, &$return_var) {
$this->assertEquals("foo", $command);
$output = "failure";
$return_var = 1;
}
);
exec("foo", $output, $return_var);
$this->assertEquals("failure", $output);
$this->assertEquals(1, $return_var);
}
}
Simply mock this function to return the text that you are trying to get into $settings. You do not need to call the executable, simply create the file or return.
For instance, assuming the function get_setting_values_from_file() returns the settings as an array, you can simply mock the function in your test to return the settings as an array. Create a test stub to mock the object that contains the get_setting_values_from_file() method, and have that mock simply return the same FALSE, 1 or 2 that the test assumed.
$stub = $this->getMock('GetSettingsClass');
$stub->expects($this->any())
->method('get_settings_from_file')
->will($this->returnValue(0));
This is from the PHPUnit manual -> http://phpunit.de/manual/3.8/en/test-doubles.html#test-doubles.stubs
Optionally, you could even bypass the call, and simply test the functions/code that works on the returns by creating the array and passing it to those functions.
Assumed Example in the main code:
...
$settings = get_setting_values_from_file( 'UserType' );
$UserType = get_user_type($settings);
return $UserType;
function get_user_type($settings)
{
if($settings !== FALSE) // Returned from your function if parameter is not found
{
switch($settings)
{
case 1:
return 'User'; // Best to use Constants, but for example here only
break;
case 2:
return 'Admin';
break;
...
}
}
else
{
return FALSE;
}
}
Now, in your test, you can simply
$this->assertFalse(get_user_type(FALSE, 'Ensure not found data is handled properly as FALSE is returned');
$this->assertEqual('User', get_user_type(1), 'Test UserType=1');
$this->assertEqual('Admin', get_user_type(1), 'Test UserType=2');
...
These work as the code does not call the function that had to mock the read from the OS, but does handle all the expected returns by calling the function processing the setting return value. Here, you have simply assumed the return from the function 'get_setting_values_from_file()' without needing the file or any mocks.
This does NOT however test reading from the file, which I would do in another test by using the setUp and tearDown to actual create a file with the values you want (fopen/fwrite) and then call your function and ensure it returns what is expected.
I hope this helps to explain what I was thinking.

Callback in function (PHP) is not working

When I execute following code I am getting this error. Why is that? What is the proper use of callbacks?
CODE (simplified)
class NODE {
//...some other stuff
function create($tags, $callback=false) {
$temp = new NODE();
//...code and stuff
if($callback) $callback($temp); //fixed (from !$callback)
return $this;
}
}
$document = new NODE();
$document->create("<p>", function($parent) {
$parent->create("<i>");
});
ERROR
Fatal error: Function name must be a string in P:\htdocs\projects\nif\nif.php on line 36
$document->new NODE();
This is not valid syntax. The accepted format would be:
$document = new NODE();
In addition to this, if you use the unary operator (!) on a false, you get true. If you use it on a Callable, you get false. As such, if (!$callback) $callback() will throw the first error of your script.
As a side note, you are reinventing the wheel. I would strongly recommend you take a look at the DOMDocument family of classes, which are doing exactly what you are currently trying to implement, albeit with fewer callbacks.
if(!$callback) $callback($temp);
If $callback is false, for sure you won't be able to call it as a callback.
if(!$callback) $callback($temp);
should probably be
if($callback) $callback($temp);
And the instanciation:
$document = new NODE();
My 2c here, type hinting may be good to use here as well.
Ex: function create($tags, callable $callback = function())
To do such a thing in php you should use function pointers and tell php which function to execute.
Look at this code.
// This function uses a callback function.
function doIt($callback)
{
$data = acquireData();
$callback($data);
}
// This is a sample callback function for doIt().
function myCallback($data)
{
echo 'Data is: ', $data, "\n";
}
// Call doIt() and pass our sample callback function's name.
doIt('myCallback');
So as you seen you can only pass the name to the function and you should predefine the function..
Similar question: How do I implement a callback in PHP?

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);
}

Categories