how to use lambda function as a condition in ternary operator - php

I'm writing a function which will be used to limit too long strings. I want to avoid duplicated code so I thought that putting almost whole function "logic" into return expression will be better than checking condition in every switch's case. But let's see code:
function test($mode, $string) {
$x = strlen("...");
$overThr = function($x, $y){strlen($string) >= $y + $x + 1;};
switch ($mode) {
case 'artist_week':
$y = 29;
break;
case 'songs_week':
$y = 31;
break;
}
return (substr($string, 0, $overThr($x, $y) ? $y : strlen($string))) . ($overThr($x, $y) ? "..." : "");
}
as you can see I want to use $overThr as a flexible condition in a ternary operator. But I can't figure out why every time $overThr is executed in "return" expression it's always returns false.
$a = test('songs_week', 'razdwatrzyczterypiecszescsiedemrazdwatrzyczterypiecszescsiedem');
echo $a;
//razdwatrzyczterypiecszescsiedemrazdwatrzyczterypiecszescsiedem
does somebody know? :)

$string is not defined within the closure and you forgot the return statement
function ($x, $y) use ($string) {
return strlen($string) >= $y + $x + 1;
};

You're using $string in the lambda, but not passing it in as a parameter or definining it as global within the lambda, so it's null/empty.

Related

PHP validate a list of constraints

I have an array of < and > constraints on variable names that I get from the user:
$constraints = array('1<x','x<5','y>4');
Where $x and $y are defined in the relevant scope.
I want to verify that all the constraints hold (return true or false)
How can I do this without using eval ?
I concocted a partial answer here. It doesn't loop, but it does support the five different comparison operators.
function lt($p1, $p2) {
return ($p1 < $p2);
}
function le($p1, $p2) {
return ($p1 <= $p2);
}
function gt($p1, $p2) {
return ($p1 > $p2);
}
function ge($p1, $p2) {
return ($p1 >= $p2);
}
function eq($p1, $pw) {
return ($p1 == $p2);
}
function apply_rule($rule, $x, $y) {
$matches = NULL;
if (!preg_match('/^([a-zA-Z0-9]+)(<|>|=|<=|>=)([a-zA-Z0-9]+)$/', $rule, $matches)) {
throw new Exception("Invalid rule: " . $rule);
}
//var_dump($matches);
$p1 = $matches[1];
$operator = $matches[2];
$p2 = $matches[3];
// check if first param is a variable
if (preg_match('/([a-zA-Z]+)/', $p1)) {
$p1 = $$p1;
}
// check if second param is a variable
if (preg_match('/([a-zA-Z]+)/', $p2)) {
$p2 = $$p2;
}
switch($operator) {
case "<":
return lt($p1, $p2);
case "<=":
return le($p1, $p2);
case ">":
return gt($p1, $p2);
case ">=":
return ge($p1, $p2);
case "=":
return eq($p1, $p2);
}
}
var_dump(apply_rule("x>=10", 10, 20));
A lot of people do know that the $ symbol in php is actually an operator that evaluates the variable.
$total_expressions = true;
foreach($constraints as $c) {
#parse the expression in to the number, and the variable
$parts = explode(">",str_replace("<",">",$c));
$i = is_numeric($parts[0]) ? 0 : 1 ;
$n = $parts[$i];
$v = $parts[1-$i];
# At this stage, $v is the variable name, and $n is the number
# This line is kinda hard coded to only ">" or "<", but you get the idea
$expression = strpos(">",$c) && $i ? $$v > $n : $$v < $n;
$total_expressions = $total_expressions && $expression;
if (!$total_expressions)
break;
}
$total_expressions would be true only if all the constraints hold.
If you just want to know that all constraints are valid, you can pass them to a function that does the checking. It can check each constraint one by one using a foreach loop. If the current constraint is not valid then it will return false and stop checking. Otherwise, if it reaches the end of the loop it will return true. The values for the variables are passed into the function as two arrays as used in str_replace().
function validate($constraints, $search, $replace) {
foreach ($constraints as $constraint) {
// replace variables in string with submitted values
$constraint = str_replace($search, $replace, $constraint);
if (strpos($constraint, '<') !== false) {
// extract parts from less than constraint
list($a, $b) = explode('<', $constraint, 2);
if ($a >= $b) {
// $a is greater than or equal to $b i.e. not less than
return false;
}
} else if (strpos($constraint, '>') !== false) {
// extract parts from greater than constraint
list($a, $b) = explode('>', $constraint, 2);
if ($a <= $b) {
// $a is less than or equal to $b i.e. not greater than
return false;
}
}
}
// no invalid constraints were found...
return true;
}
You can then use it to check your $constraints array,
// variables to search for
$search = ['x', 'y'];
// variable replacements
$replace = [5, 2];
// constraints array
$constraints = array('4<x','x<6','y>1');
// run the function
var_dump(validate($constraints, $search, $replace));
The function does assume that the data is passed to it exactly as you've described. You may want to add some checks if the data format could vary.
If you have to evaluate only simple expressions and you know in advance the number and the names of the variables then you can write a simple parser:
/**
* Parse and evaluate a simple comparison.
*
* #param string $condition e.g. 'x<4'
* #param integer $x the value of 'x'
* #param integer $y the value of 'y'
*/
function compare($condition, $x, $y)
{
// Verify that the condition uses the format accepted by this function
// Also extract the pieces in $m
$m = array();
if (! preg_match('/^(x|y|\d+)([<>])(x|y|\d+)$/', $condition, $m)) {
throw new RuntimeException("Cannot parse the condition");
}
// $m[0] is the entire string that matched the expression
// $m[1] and $m[3] are the operands (the first and the third groups)
// $m[2] is the operator (the second group in the regex)
// Replace the variables with their values in $m[1] and $m[3]
foreach (array(1, 3) as $i) {
switch ($m[$i]) {
case 'x':
$m[$i] = $x;
break;
case 'y':
$m[$i] = $y;
break;
default:
$m[$i] = (int)$m[$i];
break;
}
}
// Compare the values, return a boolean
return ($m[2] == '<') ? ($m[1] < $m[3]) : ($m[1] > $m[3]);
}
// A simple test
$x = 7;
$y = 3;
echo('$x='.$x."\n");
echo('$y='.$y."\n");
echo('1<x: '.(compare('1<x', $x, $y) ? 'TRUE' : 'FALSE')."\n");
echo('x<5: '.(compare('x<5', $x, $y) ? 'TRUE' : 'FALSE')."\n");
echo('y>4: '.(compare('y>4', $x, $y) ? 'TRUE' : 'FALSE')."\n");
The code works with integer values. To make it work with floating point values just replace (int) with (double) on the default branch of the switch statement.
The regular expression:
^ # match the beginning of the string
( # start capturing group #1
x # match the 'x' character
|y # ... OR (|) the 'y' character
|\d+ # ... OR (|) a sequence of 1 or more (+) digits (\d)
) # end capturing group #1 <-- find the captured value in $m[1]
( # start capturing group #2
[ # match any character from the range
<> # match '<' or '>'
] # end range
) # end capturing group #2 <-- find the captured value in $m[2]
(x|y|\d+) # the capturing group #3, identical to group #1
$ # match the end of the string
With simple changes the code above can be adjusted to also allow <=, >=, = (change the regex) or a list of variables that is not known in advance (pass the variables in an array indexed by their names, use $m[$i] to find the value in the array).

PHP check if is integer

I have the following calculation:
$this->count = float(44.28)
$multiple = float(0.36)
$calc = $this->count / $multiple;
$calc = 44.28 / 0.36 = 123
Now I want to check if my variable $calc is integer (has decimals) or not.
I tried doing if(is_int()) {} but that doesn't work because $calc = (float)123.
Also tried this-
if($calc == round($calc))
{
die('is integer');
}
else
{
die('is float);
}
but that also doesn't work because it returns in every case 'is float'. In the case above that should'n be true because 123 is the same as 123 after rounding.
Try-
if ((string)(int) $calc === (string)$calc) {
//it is an integer
}else{
//it is a float
}
Demo
As CodeBird pointed out in a comment to the question, floating points can exhibit unexpected behaviour due to precision "errors".
e.g.
<?php
$x = 1.4-0.5;
$z = 0.9;
echo $x, ' ', $z, ' ', $x==$z ? 'yes':'no';
prints on my machine (win8, x64 but 32bit build of php)
0.9 0.9 no
took a while to find a (hopefully correct) example that is a) relevant to this question and b) obvious (I think x / y * y is obvious enough).
again this was tested on a 32bit build on a 64bit windows 8
<?php
$y = 0.01; // some mambojambo here...
for($i=1; $i<31; $i++) { // ... because ...
$y += 0.01; // ... just writing ...
} // ... $y = 0.31000 didn't work
$x = 5.0 / $y;
$x *= $y;
echo 'x=', $x, "\r\n";
var_dump((int)$x==$x);
and the output is
x=5
bool(false)
Depending on what you're trying to achieve it might be necessary to check if the value is within a certain range of an integer (or it might be just a marginalia on the other side of the spectrum ;-) ), e.g.
function is_intval($x, $epsilon = 0.00001) {
$x = abs($x - round($x));
return $x < $epsilon;
};
and you might also take a look at some arbitrary precision library, e.g. the bcmath extension where you can set "the scale of precision".
You can do it using ((int) $var == $var)
$var = 9;
echo ((int) $var == $var) ? 'true' : 'false';
//Will print true;
$var = 9.6;
echo ((int) $var == $var) ? 'true' : 'false';
//Will print false;
Basically you check if the int value of $var equal to $var
round() will return a float. This is because you can set the number of decimals.
You could use a regex:
if(preg_match('~^[0-9]+$~', $calc))
PHP will convert $calc automatically into a string when passing it to preg_match().
You can use number_format() to convert number into correct format and then work like this
$count = (float)(44.28);
$multiple = (float)(0.36);
$calc = $count / $multiple;
//$calc = 44.28 / 0.36 = 123
$calc = number_format($calc, 2, '.', '');
if(($calc) == round($calc))
die("is integer");
else
die("is not integer");
Demo
Ok I guess I'am pretty late to the party but this is a alternative using fmod() which is a modulo operation. I simply store the fraction after the calculation of 2 variables and check if they are > 0 which would imply it is a float.
<?php
class booHoo{
public function __construct($numberUno, $numberDos) {
$this->numberUno= $numberUno;
$this->numberDos= $numberDos;
}
public function compare() {
$fraction = fmod($this->numberUno, $this->numberDos);
if($fraction > 0) {
echo 'is floating point';
} else {
echo 'is Integer';
}
}
}
$check= new booHoo(5, 0.26);
$check->compare();
Eval here
Edit: Reminder Fmod will use a division to compare numbers the whole documentation can be found here
if (empty($calc - (int)$calc))
{
return true; // is int
}else{
return false; // is no int
}
Try this:
//$calc = 123;
$calc = 123.110;
if(ceil($calc) == $calc)
{
die("is integer");
}
else
{
die("is float");
}
you may use the is_int() function at the place of round() function.
if(is_int($calc)) {
die('is integer');
} else {
die('is float);
}
I think it would help you
A more unorthodox way of checking if a float is also an integer:
// ctype returns bool from a string and that is why use strval
$result = ctype_digit(strval($float));

adding arguments in a PHP

im very new to PHP and im hoping someone here could help me out. i need to write a class, an when the below page echos it, it will show the answers.
<?php
include_once('Math.php');
$Math = new _Math();
echo $Math->calculate(2,3,"+")."<br />";
echo $Math->calculate(2,3,"-")."<br />";
echo $Math->calculate(2,3,"*")."<br />";
echo $Math->calculate(9,3,"/")."<br />";
echo $Math->calculate(9,0,"/")."<br />";
echo $Math->calculate("3",3,"+")."<br />";
echo $Math->calculate(2.5,3,"+")."<br />";
echo $Math->calculate(3,3,"test")."<br />";
I thought the code below would work, but im getting nothing but a blank screen.
<?php
class _Math {
function calculate(2,3,"+"){
$x = 2 + 3;
return $x;
}
function calculate(2,3,"-"){
$x = 2 - 3;
return $x;
}
function calculate(2,3,"*"){
$x = 2 * 3;
return $x;
}
function calculate(9,3,"/"){
$x = 9 / 3;
return $x;
}
function calculate(9,0,"/"){
$x = 9 / 0;
return $x;
}
function calculate("3",3,"+"){
$x = "3"+3;
return $x;
}
function calculate(2.5,3,"+"){
$x = 2.5+3;
return $x;
}
function calculate(3,3,"test"){
$x = 3 test 3;
return $x;
}
Im hoping someone can point me in the right direction. Hopefully im not that far off. Thanks in advance.
Function arguments must be variables, not expressions, which is explained in the manual.
This is a partial implementation:
class _Math
{
function calculate($op1, $op2, $type)
{
switch ($type) {
case '+':
return $op1 + $op2;
case '-':
return $op1 - $op2;
// ...
}
}
}
Inside the function you write a switch that will return the result based on the $type argument.
You function should look like this
function calculate(num1, num2, operation){
switch(operation){
case '+':
return $num1 + $num2;
break;
case '*':
return $num1 * $num2;
break;
// continue here :)
}
}
You only need 1 function. and multiple function with the same name will throw an error in PHP.
This is not how you define functions. Im not even sure what youre trying to do.
The round brackets contain the parameters which you hand over to the function. So you call a function like that:
$Math->calculate(2,3,"+")
These last 3 things are the parameters. You have to define the function like this:
function calculate($x, $y, $operation){
//your code
}
You cannot define multiple functions with the same name, so you have to check the operation and calculate it depending on the input. For example, +
function calculate($x, $y, $operation){
if($operation === "+") {
return $x + $y;
}
}

How to add random operator from array in PHP

I wrote this:
$num1 = mt_rand(1,5);
$num2 = mt_rand(1,5);
$operators = array(
"+",
"-",
"*",
"/"
);
$result = $num1 . $operators[array_rand($operators)] . $num2;
(My best guess is) This doesn't work as I expected because in the array the operator is a string which makes everything a string:
var_dump($result);
Gives:
string(3) "4+3"
So my question would be how would you recommend approaching this* without changing the logic it too much?
Thanks in advance!!
*Making random operation among random numbers, and if possible, the operators should be stored in an array.
I have the feeling my title is not correctly describing the situation but I could not come up with a better idea, I'm open to suggestions :)
Of course, you could use eval to do this, but I certainly won't settle for such a solution.
I'd suggest defining a bunch of functions that take in two params and return a result, then use call_user_func_array on the result of array_rand.
function add($x, $y) { return $x + $y; }
function subtract($x, $y) { return $x - $y; }
function multiply($x, $y) { return $x * $y; }
function divide($x, $y) { return $x / $y; }
$operators = array('add', 'subtract', 'multiply', 'divide');
//...
$result = call_user_func_array($operators[array_rand($operators)], array($x, $y));
<?php
$num1 = mt_rand(1, 5);
$num2 = mt_rand(1, 5);
$operators = array(
"+",
"-",
"*",
"/"
);
switch ($operators[array_rand($operators)]) {
case "+":
$result = $num1 + $num2;
break;
case "-":
$result = $num1 - $num2;
break;
case "*":
$result = $num1 * $num2;
break;
case "/":
$result = $num1 / $num2;
break;
}
var_dump($result);
The clean solution would be to have a code branch for each operator, e.g.
function do_something($num1, $num2, $operator) {
switch ($operator) {
case '+':
return $num1 + $num2;
case '-':
return $num1 - $num2;
case '*':
return $num1 * $num2;
case '/':
return $num1 / $num2;
default:
throw new Exception('Unknown operator: '.$operator)
}
}
If you have more operators, you should create a map of operator => function and dynamically call the functions, for example:
$ftable = array(
'+' => 'fn_add',
'-' => 'fn_sub',
'*' => 'fn_mul',
'/' => 'fn_div'
);
function fn_add($a, $b) { return $a + $b; }
function fn_sub($a, $b) { return $a - $b; }
function fn_mul($a, $b) { return $a * $b; }
function fn_div($a, $b) { return $a / $b; }
function do_something($num1, $num2, $operator) {
global $ftable;
if (array_key_exists($operator, $ftable)) {
return call_user_func($ftable[$operator], $num1, $num2);
}
else {
throw new Exception('Unknown operator: '.$operator)
}
}
And of course, the unclean (slow, potentially dangerous) solution would be to use eval().
Create a function for each operation, then store operator => function name in an array.

How can I simplfy this logic

I'm having trouble simplifying this conditional statements logic. Is there a more effervescent way of writing this?
if(($x || $a) && ($x || $y))
{
if($x){
return true;
}
}
return false;
if ($x) return true;
return false;
According to your statement, you only return true if $x is true, therefore that is the only statement you really need to check for, correct? The variables $a and $y are completely irrelevant.
Edit: Same thing as:
return (bool) $x;
If you only return true if $x is true, then the rest of the code is irrelevant. Thus,
return (bool) $x;
EDIT: Oops... bool is a cast, not a function.
The condition of the outer if, ($x || $a) && ($x || $y), is equivalent to $x || ($a && $y). When we conjunct that with the condition that $x must also be true (inner if), we get ($x || ($a && $y)) && $x. And that is equivalent to $x && $x || $x && $a && $y which can be reduced to $x || $x && $a && $y. In both OR branches $x must be true to proceed. But if the $x in the right branch is true, the whole condition is already true.
So the only variable that needs to be true is $x:
return (bool) $x;
Like several people have already said, only $x matters in your code. I guess the shortest possible code is:
return $x
if($x && ($a || $y))
return true;
return false;
if(($x && $a && $y)
{
return true;
}
return false;
EDIT : it is simply return $x;
You could write this as a one line expression...
return $x;
regardless of $a and $y, $x has to be true to return true
if($x){
return true;
}
return false;
?
Edit:
return $x

Categories