php functional-php library less_than function - php

I saw in source code of php-functional library such function :
function less_than($b)
{
return function ($a ) use ($b) {
return $a < $b;
};
}
I can't get there $a comes from. How is this going to work?
We pass only $b to function less than and $a is undefined.
This is the link to source code where I took it from.

The idea of functional programming is that functions are first-class objects. So you can pass functions as parameters; and you can return functions.
So here you can construct a function:
$func_less = less_than(3);
So we basically construct a function like:
$func_less = function ($a) {
return $a < 3;
};
and now $func_less is a function that takes a parameter $a and checks if that $a is less than three. For example:
php > $func_less_three = less_than(3);
php > var_dump($func_less_three(2));
bool(true)
php > var_dump($func_less_three(14));
bool(false)
So first we construct a function $func_less_three, then we call that function with two numbers 2 and 14. Since 2 is less than 3, it returns bool(true) on the first call, and since 14 is not less than 3, it return bool(false) on the second call.
In most functional programming languages like Haskell, all functions take exactly one parameter. So instead of adding two numbers together, one first constructs a function that adds a (in that function) constant value to a parameter.

Related

Evaluate concatonated operator with numbers

I'm struggling with a small piece of code that doesn't want to evaluate itself :
$t = 5;
$s = "<=";
$r = 6;
var_dump($t.$s.$r);
Here the var_dump return "5<=6" which make sense but I just want it to tell me if 5 is inferior or equal to 6 with a boolean.
I wanted to know if there was an other way to get this boolean beside using an eval() or a switch throught all the possible operator
Thanks in advance.
If you want a safe and flexible solution, this allows you to define a method which is executed depending on the operator matching the key in an array, it only works with two operands, but the last one in the examples # just multiplies the first value by 4 and returns the value...
$operators = [ "<=" => function ($a, $b) { return $a <= $b;},
"<" => function ($a, $b) { return $a < $b;},
">=" => function ($a, $b) { return $a >= $b;},
">" => function ($a, $b) { return $a > $b;},
"#" => function ($a) { return $a * 4; }];
$t = 5;
$s = "<=";
$r = 6;
var_dump($operators[$s]($t,$r));
$s = "<";
var_dump($operators[$s]($t,$r));
$s = ">=";
var_dump($operators[$s]($t,$r));
$s = ">";
var_dump($operators[$s]($t,$r));
$s = "#";
var_dump($operators[$s]($t,$r));
gives...
/home/nigel/workspace2/Test/t1.php:14:
bool(true)
/home/nigel/workspace2/Test/t1.php:17:
bool(true)
/home/nigel/workspace2/Test/t1.php:20:
bool(false)
/home/nigel/workspace2/Test/t1.php:23:
bool(false)
/home/nigel/workspace2/Test/t1.php:26:
int(20)
It's a bit convoluted, but also extensible and safe.
while it is generally not a good idea to have code usch as this (evaluating code that is sstored as plaintext), there is a function for exactly this: eval().
eval() does what you expect PHP to do naturally: evaluate valid code stored in a string.
eval("var_dump(".$t.$s.$r.");"); will do the job - however, since any code inside those variables is executed without question, it can be a security risk, or at least introduce some hard-to-debug errors.
(the extra quoting and the ; are needed to make the code inside eval actually valid PHP code)

What is the reason of returning -1 instead of lets say 0 at the end of this function's code?

I am talking about the second "return -1;" on the 12th line of the code. This gets reached only if two sets of numbers are exactly the same, like when comparing '192.167.11' to '192.167.11'. I will also add that using range(0,2) would be a better option for this piece of code (range(0,3) produces errors if two elements happen to be the same; I did not change that as this is the original code example from PHP Array Exercise #21 from w3resource.com).
<?php
function sort_subnets($x, $y){
$x_arr = explode('.', $x);
$y_arr = explode('.', $y);
foreach (range(0, 3) as $i) {
if ($x_arr[$i] < $y_arr[$i]) {
return -1;
} elseif ($x_arr[$i] > $y_arr[$i]) {
return 1;
}
}
return -1;
}
$subnet_list =
array('192.169.12',
'192.167.11',
'192.169.14',
'192.168.13',
'192.167.12',
'122.169.15',
'192.167.16'
);
usort($subnet_list, 'sort_subnets');
print_r($subnet_list);
?>
Returning "-1" would move the second element (the same as the first in the current $x and $y pair) towards the higher index of the array (down the array). Why not return "0" and keep everything as is if the two elements are exactly the same? Is there any reason for returning the "-1" maybe based on how the usort() works (or any other factor of this)?
Thanks.
EDIT:
I think that this is Insertion Sort (array size 6-15 elements; normally it would be Quicksort).
If the two elements are the same, there's no difference between swapping the order and keeping the order the same. So it doesn't make a difference what it returns in that case.
You're right that 0 is more appropriate. This would be more important if usort were "stable". But the documentation says
Note:
If two members compare as equal, their relative order in the sorted array is undefined.
To illustrate the excellent point of #Don'tPanic:
<?php
function sort_subnets($x, $y){
$x_arr = explode('.', $x);
$y_arr = explode('.', $y);
return $x_arr <=> $y_arr;
}
$subnet_list =
array('192.169.12',
'192.167.11',
'192.169.14',
'192.168.13',
'192.167.12',
'122.169.15',
'192.167.16'
);
usort($subnet_list, 'sort_subnets');
print_r($subnet_list);
See live code
Note the use of the "spaceship" operator, namely <=> which offers a conciseness that spares one from having to write code like the following in a function:
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
Lastly, note that the user-defined callback for usort() makes use of ternary logic because sometimes as in the case of sorting bivalent logic is insufficient. Yet, usort() itself utilizes two-part logic, returning TRUE on success and FALSE on failure.

PHP "use" over additional parameters for closures?

In what situation is using the use keyword with a closure more beneficial then just passing along additional parameters to the closure?
Example #1:
$myClosure = function($var1, $var2) use ($var3){
//Some code
}
Example #2:
$myClosure = function($var1, $var2, $var3){
//Some code
}
Like all things it probably depends, but I don't see any functional difference between the two. Can anyone suggest a situation or example where one example would be preferred over the other?
I don't see any functional difference between the two.
The arguments are provided by the caller of the function. If you are the caller and can provide all the necessary arguments, then there is basically no difference*.
However, you might be passing the function somewhere else, so you are not caller and do not control which arguments are passed. This is the situation that closures solve: You can make values available without calling the function.
See also In PHP 5.3.0, what is the function "use" identifier? .
*: The variables that are bound through use are defined at definition time. So if the value of the variable changes, there will be a difference:
$a = 1;
$b = 2;
$c = 3;
$f1 = function($a, $b) use ($c) {
echo $a, $b, $c;
};
$f2 = function($a, $b, $c) {
echo $a, $b, $c;
};
$c = 42;
$f1($a, $b); // 1, 2, 3
$f2($a, $b, $c); // 1, 2, 42
Say you're using a closure with pre-defined parameters, like preg_replace_callback for example, and you want to use a variable from other places in your code, you'd use the use keyword
$myvar = "hello";
$text = "";
$text = preg_replace_callback('/regex/', function($matches) use ($myvar) {
return $myvar . " " . $matches[1] . "!";
}, $text);
It's a great way to use a variable within a closure with pre-defined parameters, which do not have access to variables outside the closure

php Anonymous function

When I was reading questions for Zend Certified PHP Engineer 5.5 I saw question about anonymous function but I need to explan how it work.
function z($x)
{
return function($y) use ($x)
{
return str_repeat( $y , $x );
};
}
$a = z(2);
$b = z(3);
echo $a(3).$b(2);
The output for this code is:
33222
But in function header there is only $x parameter from where $y got there value!
Function z creates and returns a new function, but an anonymous one. That new function is defined so that it has one argument - $y. However, this anonymous function also uses argument $x from a function z.
To make it simple, function z basically creates a function which can repeat any string, but a fixed number of times. The number of times a string is repeated is determined by the value of argument $x in z.
So, calling z(2) creates a new function which is functionally equivalent to writing
function repeat_two_times($y) {
return str_repeat($y, 2);
}
In you example, hard coded value 2 is determined by the value of $x.
You can read more about this in the documentation. The principle displayed by the example can be quite useful for creating partial functions like add5, inc10, ...
Firstly, you initialize function z:
$a = z(2);
$x in the example is set to 2, so the returned function (anonymous function, also called closure) can now be read as (because $x is used):
$a = function($y) {
return str_repeat($y, 2);
}
When invoking this function:
echo $a(3);
You are supplying this return function with the parameter 3 ($y).
The output is: 33
Anonymous functions are also known as Closures.
You ask where $y gets its value. The code example is difficult to decipher because you use 2s and 3s everywhere. Things would be clearer if your last lines were
$a = z(2);
$b = z(3);
echo $a('A').$b('B');
That would result in:
AABBB
But let's follow your code. Notice that there are two related function calls
$a = z(2);
and
echo $a(3);
calling function z() with argument 2 returns a function (that is assigned name $a) where line
return str_repeat($y, $x);
is in reality :
return str_repeat($y, 2);
now, you call that function $a() with argument 3. That 3 (value of $y) is repeated two times
The same analysis applies to the other related function calls:
$b = z(3);
...
echo ... $b(2);
But in this case 2 is repeated 3 times
function z($x)
{
return function($y) use ($x)
{
return str_repeat( $y , $x );
};
}
$a = z(2);// here you are setting value of x by 2
$b = z(3);// here you are setting value of x by 3
echo $a(3).$b(2);// here $a(3) 3 is value of y so it becomes str_repeat( 3 , 2 ); which is 33

How to treat string as a string and not as an int in PHP

I was reading PHP manual and I came across type juggling
I was confused, because I've never came across such thing.
$foo = 5 + "10 Little Piggies"; // $foo is integer (15)
When I used this code it returns me 15, it adds up 10 + 5 and when I use is_int() it returns me true ie. 1 where I was expecting an error, it later referenced me to String conversion to numbers where I read If the string starts with valid numeric data, this will be the value used. Otherwise, the value will be 0 (zero)
$foo = 1 + "bob3"; /* $foo is int though this doesn't add up 3+1
but as stated this adds 1+0 */
now what should I do if I want to treat 10 Little Piggies OR bob3 as a string and not as an int. Using settype() doesn't work either. I want an error that I cannot add 5 to a string.
If you want an error, you need to trigger an error:
$string = "bob3";
if (is_string($string))
{
trigger_error('Does not work on a string.');
}
$foo = 1 + $string;
Or if you like to have some interface:
class IntegerAddition
{
private $a, $b;
public function __construct($a, $b) {
if (!is_int($a)) throw new InvalidArgumentException('$a needs to be integer');
if (!is_int($b)) throw new InvalidArgumentException('$b needs to be integer');
$this->a = $a; $this->b = $b;
}
public function calculate() {
return $this->a + $this->b;
}
}
$add = new IntegerAddition(1, 'bob3');
echo $add->calculate();
This is by design as a result of PHP's dynamically typed nature and of course lack of an explicit type declaration requirement. Variable types are determined based on context.
Based on your example, when you do:
$a = 10;
$b = "10 Pigs";
$c = $a + $b // $c == (int) 20;
Calling is_int($c) will of course always evaluate to a boolean true because PHP has decided to convert the result of the statement to an integer.
If you're looking for an error by the interpreter, you won't get it since this is, like I mentioned, something built into the language. You might have to write a lot of ugly conditional code to test your data types.
Or, if you want to do that for testing arguments passed to your functions - that's the only scenario which I can think of where you might want to do this - you can trust the client invoking your function to know what they are doing. Otherwise, the return value can simply be documented to be undefined.
I know coming from other platforms and languages, that might be hard to accept, but believe it or not a lot of great libraries written in PHP follow that same approach.

Categories