How to write isEven() function as callable function? - php

I am learning PHP using reviewing some complete PHP projects. (I know that this is a bad way, but my goal is not to be a PHP programmer!) Anyway, I faced with the following function that is weird a little to me:
function filterIt($filter): callable {
return function ($value) use ($filter) {
return filter_var($value, $filter) !== false;
};
}
I don't know what this function do and why it has been witter in such a way that a function is inside of another function! inner function returns something and main function also. Why we need such complicated function? or maybe one can make it simpler?
For this reason I want to write isEven() function as callable function like above. But I have no idea!
I don't know what that function do, but by mimicking from that:
function isEven($num): callable {
return function () use ($num) {
return $num % 2 == 0;
};
}
I couldn't debug this using var_dump or print_r .

Not sure how you are calling this in you're test, but as the function is actually returning a callable you would be able to debug it once you run it like this:
<?php
function isEven($num): callable {
return function () use ($num) {
return $num % 2 == 0;
};
}
var_dump(isEven(14)());

IMO the summary of the filterIt() function is "give me an anonymous function that filters based on $filter", and then that callable is likely passed somewhere else to be applied. I would venture to guess that the author wrote this function as a shorthand so that they did not need to write out the anonymous function definition over and over for different values of $filter.
Below is a simplified example of such behaviour:
class ExampleCollection {
protected $filters = [];
public function __construct(protected array $items) {}
public function addFilter(callable $filter) {
$this->filters[] = $filter;
}
public function getFiltered() :\Generator {
foreach($this->items as $item) {
foreach($this->filters as $filter) {
if( $filter($item) ) {
continue 2;
}
}
yield $item;
}
}
}
function makeMultipleFilter(int $value) :callable {
return function($a)use($value) {
return $a % $value === 0;
};
}
$c = new ExampleCollection([1,2,3,4,5,6,7,8,9,10]);
// add filters to exclude multiples of 3 and 4
$c->addFilter(makeMultipleFilter(3));
$c->addFilter(makeMultipleFilter(4));
foreach($c->getFiltered() as $item) {
printf("Got: %d\n", $item);
}
Output:
Got: 1
Got: 2
Got: 5
Got: 7
Got: 10
But I agree with Chris Haas' comment that the author's intent is not always obvious and is best asked of them, if possible. Further to that, not all code is exemplary, even if someone exemplary happens to have written it. Everyone writes themselves into a corner sometimes and has to resort to a confusing and/or ugly piece of code to get around it. Which is not to say that this is what that is, though it is somewhat confusing on first read.

Related

In PHP, can you split a function up so it auto-detects a variable function adjusts the logic accordingly

I'm imagining something like:
Say you have Model->Find('column_name', 'value') and you want to call database records with the field name as part of the function call, e.g. Model->FindByEmail('value')
Could you make it so your class was smart enough to know that all Model->FindByX() calls are really just a dynamic wrapper for Model->Find('column_name', 'value')?
You can use PHP's Magic Method __call()
class MyClass {
public function find($key, $value) {
...
}
public function __call($name, $args) {
if (strpos($name, 'findBy') === 0 && count($args) === 1) {
$key = substr($name, 6); //skip 6 characters of "findBy"
//if you want the key lower case:
// $key = strtolower($key);
return $this->find($key, $args[0]);
}
return null;
}
}
But this is slower in performance than a normal call, it can also generate confusion and most PHP IDEs will mark it as warning because it is difficult to debug.

PHP method chain with loop

Hi I am trying to build a class to emulate Gouette as a learning exercise:
https://github.com/FriendsOfPHP/Goutte/blob/master/README.rst
I think I am on the right track by using method chaining which I think they are doing, what I'm not sure of is how they do something like this:
$crawler->filter('h2 > a')->each(function ($node) {
print $node->text()."\n";
});
Would this be some kind of anonymous function?
This is my code so far:
class Bar
{
public $b;
public function __construct($a=null) {
}
public function chain1()
{
echo'chain1';
return $this;
}
public function loop($a)
{
echo'chain2';
return $this;
}
public function chain2()
{
echo'chain2';
return $this;
}
}
$a=array('bob','andy','sue','rob');
$bar1 = new Bar();
$bar1->chain1()->loop($a)->chain2();
I've tried to simplify the code to show just this one aspect of what your after...
class Bar
{
private $list;
public function __construct($a=null) {
$this->list = $a;
}
public function each( callable $fn )
{
foreach ( $this->list as $value ) {
$fn($value);
}
return $this;
}
}
$a=array('bob','andy','sue','rob');
$bar1 = (new Bar($a))->each(function ($value) {
print $value."\n";
});
As you can see, I've created the object with the list you have, and then just called each() with a callable. You can see the function just takes the passed in value and echoes it out.
Then in each() there is a loop across all the items in the list provided in the constructor and calls the closure ($fn($value);) with each value from the list.
The output from this is...
bob
andy
sue
rob
As for the chained calls, the idea is (as you've worked out) is to return an object which will be the start point for the next call. Some use $this (as you do) some systems (like Request commonly does) return a NEW copy of the object passed in. This is commonly linked to the idea of immutable objects. The idea being that you never change the original object, but you create a new object with the changes made in it. Psr7 Http Message, why immutable? gives some more insight into this.

PHP use of anonymous functions

So I'm really confused about anonymous functions in PHP, I want to know if anonymous functions are mainly used as a matter of taste or coding style.
I'm asking this because you can achieve the same result without a callback function and less code.
So here is some test code:
$output = 10;
$people = (new People(new John));
//VERSION 1 ANONYMOUS FUNCTION
$people->run(function ($value) use(&$output){
$output = $output + $value;
});
var_dump($output); //RESULT => 20
//VERSION 2 WITHOUT ANONYMOUS FUNCTION
var_dump($people->run() + $output); //RESULT => 30
You can run and see the full code here:
https://www.tehplayground.com/IhWJJU0jbNnzuird
<?php
interface HumanInterface
{
public function hello();
}
class People
{
protected $person;
protected $value;
public function __construct(HumanInterface $person)
{
$this->person = $person;
return $this;
}
public function run(callable $callback = null, $name = null)
{
$this->value = 10;
if(is_callable($callback)) {
return call_user_func($callback, $this->value);
}
return $this->value;
}
}
class John implements HumanInterface
{
public function hello()
{
return 'hi i am john';
}
}
$output = 10;
$people = (new People(new John));
$people->run(function ($value) use(&$output){
$output = $output + $value;
});
var_dump($output);
var_dump($people->run() + $output);
So my question is: why use an anonymous function? Is it a matter of
personal choice?
Anonymous functions or „Closures“ are very useful if it is used as a one-time callback. If you use PHP's usort-method for example. The second parameter can be a Closure. So instead of writing a named function which is used once and then never again you use a Closure.
IMHO this is the only way to use Closures: as a callback.
Anonymous functions are useful to pass around for later execution or to other code accepting functions. Using them can dramatically reduce the code needed to do things.
Imagine you have a UserCollection object that uses a generic Collection underneath. You want to reduce the UserCollection to just the Users from a certain country. So you could add a method findByCountry() on the UserCollection:
public function findByCountry($country) : UserCollection {
$subset = new UserCollection;
foreach ($this->users as $user) {
if ($user->country === $country) {
$subset->add($user);
}
}
return $subset;
}
This is all fine, but additional finder methods will all do the same: iterate and collect into the subset with only the criteria being different. So a lot of boilerplate code.
You can separate the boilerplate from the criteria easily by adding a method find(callable $callback) on the underlying Collection, like this:
public function find(callable $criteria) : Collection {
$subset = new Collection;
foreach ($this->users as $user) {
if ($criteria($user)) {
$subset->add($user);
}
}
return $subset;
}
This is a generic finder. Now your code in the UserCollection will only contain the actual criteria:
public function findByCountry($country): UserCollection {
return $this->subset(function(User $user) {
return $user->country === $country;
});
}
private function subset($criteria): UserCollection {
return new UserCollection($this->allUsers->find($criteria));
}
By separating the criteria from the boilerplate, it's much easier to grasp that you are trying to find users by country. There is no iteration code distracting from the actual criteria. So it becomes easier to understand and less effort to write. Also, you cannot accidentally mess up the iteration because it's defined elsewhere.
When using anonymous functions like this, they are very similar to using the Strategy Pattern or a FilterIterator. The notable difference being that you are creating them on the fly.
Note that you have to differentiate between Lambdas and Closures. I deliberately ignored the difference for this answer.

PHP Calling a callback function from within Object method

I am building a scheduler that will take a callback function and will execute that function a given amount of times, and in between a given amount of delay. Below is that the interface for what the functionality looks like.
Side note I am using the Laravel Framework;
public function testBasicTest()
{
$count = 0;
$schedule = new NodeScheduler();
$schedule->retries(2)->delay(100000)->do(function() use ($count) {
$count++;
});
$this->assertEquals($count === 1);
}
This is my test for this piece of functionality and as you can see i want count to equal 2 by the end of it.
My class looks like this;
class NodeScheduler
{
protected $retries = 1;
protected $milliseconds = 10000;
public function __construct()
{
return $this;
}
public function retries($numberOfRetries)
{
$this->retries = $numberOfRetries;
return $this;
}
public function delay($milliSeconds)
{
$this->milliSeconds = $milliSeconds;
return $this;
}
public function do($callback)
{
for($i = 0; $i < $this->retries; $i++){
$callback(); // <<<<<< How Do I Inject The $count Variable Here?
usleep($this->milliseconds);
}
return;
}
}
My test fails with:
Failed asserting that 2 matches expected 0.
Strangely I don't get $count is undefined.
I think i am close, any help greatly appreciated
When you use() a variable from the outer scope inside a function, this creates a copy of the variable into the function's inner scope (an exception is if you're use()ing an object).
If you want to import a variable from the outer scope and modify it, you'll need to pass it in by reference:
$schedule->retries(2)->delay(100000)->do(function() use (&$count) {
$count++;
});
Edit: Also, what #Arno and #Oniyo pointed out: either use assertEquals(1, $count) or use assertTrue($count === 1)
I think you are doing two things wrong
Firstly: As #Arno pointed out,
$this->assertEquals($expected, $actual);
Secondly: From what I see in your code, the loop will run $this->retries's iterations. So, $this->assertEquals($expected, $actual) should be
$this->assertEquals(2, count);
Good luck man!

Lazy Function Definition in PHP - is it possible?

In JavaScript, you can use Lazy Function Definitions to optimize the 2nd - Nth call to a function by performing the expensive one-time operations only on the first call to the function.
I'd like to do the same sort of thing in PHP 5, but redefining a function is not allowed, nor is overloading a function.
Effectively what I'd like to do is like the following, only optimized so the 2nd - Nth calls (say 25-100) don't need to re-check if they are the first call.
$called = false;
function foo($param_1){
global $called;
if($called == false){
doExpensiveStuff($param_1);
$called = true;
}
echo '<b>'.$param_1.'</b>';
}
PS I've thought about using an include_once() or require_once() as the first line in the function to execute the external code just once, but I've heard that these too are expensive.
Any Ideas? or is there a better way to tackle this?
Use a local static var:
function foo() {
static $called = false;
if ($called == false) {
$called = true;
expensive_stuff();
}
}
Avoid using a global for this. It clutters the global namespace and makes the function less encapsulated. If other places besides the innards of the function need to know if it's been called, then it'd be worth it to put this function inside a class like Alan Storm indicated.
Have you actually profiled this code? I'm doubtful that an extra boolean test is going to have any measurable impact on page rendering time.
you can do conditional function definiton.
if( !function_exists('baz') )
{
function baz( $args ){
echo $args;
}
}
But at present, a function becomes a brick when defined.
You can use create_function, but I would suggest you DONT because it is slow, uses lots of memory, doesn't get free()'d untill php exits, and is a security hole as big as eval().
Wait till PHP5.3, where we have "closures" http://wiki.php.net/rfc/closures
Then you'll be permitted to do
if( !isset( $baz ) )
{
$baz = function( $args )
{
echo $args;
}
}
$baz('hello');
$baz = function( $args )
{
echo $args + "world";
}
$baz('hello');
Upon further reading, this is the effect you want.
$fname = 'f_first';
function f_first( $even )
{
global $fname;
doExpensiveStuff();
$fname = 'f_others';
$fname( $even );
/* code */
}
function f_others( $odd )
{
print "<b>".$odd."</b>";
}
foreach( $blah as $i=>$v )
{
$fname($v);
}
It'll do what you want, but the call might be a bit more expensive than a normal function call.
In PHP5.3 This should be valid too:
$func = function( $x ) use ( $func )
{
doexpensive();
$func = function( $y )
{
print "<b>".$y."</b>";
}
$func($x);
}
foreach( range(1..200) as $i=>$v )
{
$func( $v );
}
( Personally, I think of course that all these neat tricks are going to be epically slower than your earlier comparison of 2 positive bits. ;) )
If you're really concerned about getting the best speed everywhere
$data = // some array structure
doslowthing();
foreach( $data as $i => $v )
{
// code here
}
You may not be able to do that however, but you've not given enough scope to clarify. If you can do that however, then well, simple answers are often the best :)
Please don't use include() or include_once(), unless you don't care if the include() fails. If you're including code, then you care. Always use require_once().
If you do wind up finding that an extra boolean test is going to be too expensive, you can set a variable to the name of a function and call it:
$func = "foo";
function foo()
{
global $func;
$func = "bar";
echo "expensive stuff";
};
function bar()
{
echo "do nothing, i guess";
};
for($i=0; $i<5; $i++)
{
$func();
}
Give that a shot
PHP doesn't have lexical scope, so you can't do what you want with a function. However, PHP has classes, which conceptually works in exactly the same way for this purpose.
In javascript, you would do:
var cache = null;
function doStuff() {
if (cache == null) {
cache = doExpensiveStuff();
}
return cache;
}
With classes (In PHP), you would do:
class StuffDoer {
function doStuff() {
if ($this->cache == null) {
$this->cache = $this->doExpensiveStuff();
}
return $this->cache;
}
}
Yes, class-based oop is more verbose than functional programming, but performance-wise they should be about similar.
All that aside, PHP 5.3 will probably get lexical scope/closure support, so when that comes out you can write in a more fluent functional-programming style. See the PHP rfc-wiki for a detailed description of this feature.
How about using local static variables?
function doStuff($param1) {
static $called = false;
if (!$called) {
doExpensiveStuff($param1);
$called = true;
}
// do the rest
}
If you need to do expensive stuff only once for given parameter value, you could use an array buffer:
function doStuff($param1) {
static $buffer = array();
if (!array_key_exists($param1, $buffer)) {
doExpensiveStuff($param1);
$buffer[$param1] = true;
}
// do the rest
}
Local static variables are persistent across function calls. They remember the value after return.
Any reason you're commited to a functional style pattern? Despite having anonymous functions and plans for closure, PHP really isn't a functional language. It seems like a class and object would be the better solution here.
Class SomeClass{
protected $whatever_called;
function __construct(){
$this->called = false;
}
public function whatever(){
if(!$this->whatever_called){
//expensive stuff
$this->whatever_called = true;
}
//rest of the function
}
}
If you wanted to get fancy you could use the magic methods to avoid having to predefine the called booleans. If you don't want to instantiate an object, go static.

Categories