php inline function like .net - php

i want to write an inline function in php like below
forexample :
$c = getCountry();
$b = getZones();
$a = [
'x' => function() use ($c, $b)
{
if ( isset($c[0]) )
return getZonesByCountryId($c[0]['id']);
else
return $b;
}
];
i get this error : "Object of class Closure could not be converted to string"
i write inline function in .net like i did it above. please help me !!!

The value of 'x' is going to be a function; the anonymous function itself will be assigned to 'x', not its return value. To assign its return value, you need to actually execute the function:
$a = ['x' => call_user_func(function() use ($c, $b) {
if (isset($c[0])) {
return getZonesByCountryId($c[0]['id']);
} else {
return $b;
}
})];
However, in this particular case it makes absolutely no sense to use such a complicated solution, when this will do just fine:
$a = ['x' => isset($c[0]) ? getZonesByCountryId($c[0]['id']) : $b];

Related

How to use arrow functions in PHP?

I got to know about arrow functions in PHP 7.4. I tried using them like
<?php
$num = 1;
$arrowfunction = () => {
return $num + 1;
}
echo $arrowfunction();
Because I saw the => operator in the pull request. Just like javascript.
I expected '2' as the output but this didn't work! I got
Parse error: syntax error, unexpected ')' in /test.php on line 3
Arrow functions in PHP are introduced in PHP 7.4. They are a little different.
The fn keyword
The new fn keyword is now a reserved keyword.
Previously, we used to continue using function keyword.
$add = function ($valone,$valtwo) {
return $valone + $valtwo;
};
$add(1,2) // 3
With the advent of new arrow functions:
$add = fn($valone,$valtwo) => $valone + $valtwo;
$add(1,2) // 3
Parent scope
Earlier, we have to follow with the usage of the keyword use for the involvement of a variable from the parent scope.
$y = 1;
$fn = function ($x) use ($y) {
return $x + $y;
};
echo $fn(2); // 3
The expression defined in the parent scope will be implicitly captured by-value.
$y = 1;
$fn = fn($x) => $x + $y;
echo $fn(2); // 3
The above follows for $this variable inside class methods.
class foo {
public function test() {
$context = fn() => var_dump($this);
$context();
}
}
$test = new foo();
$test->test(); // object(foo)#1 (0) { }
Just like previously, we used to perform our operations by using the use keyword to take a variable from the parent scope, so this means that we cannot write the value of the variable from the function into the upper scope.
$y = 1;
$fn = fn() => $y++;
$fn(); // Has no effect
echo $y // 1
If we are thinking of assigning another variable's value from the closure then this also will not work
$y = 1;
$f = 0;
$fn = fn() => $f = $y + 1;
$fn();
echo $f; // 0
Function signatures
This is completely new in PHP, this allows us the define the type of function, variable and the value the function is returning
fn(int $x) => $x; // the argument type must be (int)
fn(): int => $x; // type of return value (int)
Errors are thrown when the defined argument type is not placed in the argument when calling the function. The error can be caught by using the TypeError type
$var = 10;
$int_fn = fn(int $x): int => $x;
var_dump($int_fn($var)); // int(10)
try {
$int_fn("foo");
} catch (TypeError $e) {
echo $e->getMessage(), "\n"; // Argument 1 passed to {closure}() must be of the type int, string given, called in x on line y
}
By PHP 7.1, they support the ?type in arguments which allows the argument to be null too.
$funn = fn(?int... $args): array => $args;
var_dump($funn(20, null, 30)); // Array(3) { [0]=> int(20) [1]=> NULL [2]=> int(30) }
If you supply a string or anything else rather than int to the above function, then you'll get an error
Argument passed to {closure}() must be of the type int or null, string given, called in x on line y
Nested arrow functions
$var = 6;
var_dump((fn() => fn() => $var)()()); // int(6)
var_dump((fn() => function() use($var) { return $var; })()()); // int(6)
Any possible errors inside the closure are not thrown unless called
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
$b = 1;
fn() => $b + $c; // no error, nothing
ini_set('display_errors', 1);
ini_set('display_startup_errors', 1);
error_reporting(E_ALL);
$b = 1;
(fn() => $b + $c)(); // Notice: Undefined variable: c in the location on line x
If error reporting is off then you'll just get int(1)
How to use PHP. 7.4 now? For quick online testing just paste these code there
For your native system, I Just cloned this branch of php-src and compiled it using GCC and make. I did my testing via a test.php file and command line to check if everything works.
Core reference - https://wiki.php.net/rfc/arrow_functions_v2
The arrow functions can make your code shorter and more readable in some situations. They were primarily designed with a thought of using them for simple callbacks. As an example consider usort() which takes in a callback function as a user parameter.
Prior to PHP 7 you had to do something like this to define your own callback for usort():
// old syntax prior to PHP 7
function cmp($a, $b) {
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
}
$a = [3, 2, 5, 6, 1];
usort($a, "cmp");
foreach ($a as $key => $value) {
echo "$key: $value\n";
}
PHP 7 has added a spaceship operator and now thanks to arrow functions you can make your code much cleaner.
// New syntax since PHP 7.4
$a = [3, 2, 5, 6, 1];
usort($a, fn($a, $b) => $a<=>$b);
foreach ($a as $key => $value) {
echo "$key: $value\n";
}
Try it online at 3v4l.org
Anonymous functions in PHP can be quite verbose, even when they only perform a simple operation, hence the reason for a shorter syntax. As another example consider the following function:
// Returns an array with each element squared - old syntax
function array_square($arr) {
return array_map(function($x) { return $x*$x; }, $arr);
}
// Returns an array with each element squared - new syntax
function array_square($arr) {
return array_map(fn($x) => $x**2, $arr);
}
print_r(array_square([1,2,3,4,5]));
Reducing the unnecessary syntax helps to understand the real purpose of the code, but keep in mind that shorter does not always mean cleaner! I would recommended to treat arrow functions with the same caution as ternary operators. Only use them when you know it helps readability, not just to make your code shorter.

Difference between "use" and passing a parameter to controller function

I don't have a specific problem, just looking to deepen my understanding of what's going on with Silex and with some new-ish PHP features in general. This is based off the code samples on the "usage" page of the Silex documentation:
$blogPosts = array(
1 => array(
'date' => '2011-03-29',
'author' => 'igorw',
'title' => 'Using Silex',
'body' => '...', );
$app->get('/blog/{id}', function (Silex\Application $app, $id) use ($blogPosts) {
//do stuff
}
Questions
What is the difference here between passing the $app and $id as parameters to the function, and use-ing the $blogPosts variable?
Could $blogPosts also have been passed as a parameter to the function?
Also, I more commonly see use ($app). What is the difference between use-ing the $app and passing it is a parameter?
This has nothing to do with silex and everything to do with "some new-ish PHP features".
You are creating an anonymous function (also called a closure), reusable several times with different $app and $id values, BUT with only the same $blogPosts value.
<?php
$a = "a";
$b = "b";
$c = function ($d) use ($b) {
echo $d . "." . $b . PHP_EOL;
};
$b = "c";
$e = function ($d) use ($b) {
echo $d . "." . $b . PHP_EOL;
};
$c($a); // prints a.b, and not a.c
$e($a); // prints a.c
Here, i'm building a function with $b, and once it is build, I use it with variables that do not have to be named the same way the function's argument is named.
Maybe this makes it more transparent
<?php
$a = "a1";
$b = "b1";
$f = function ($x) use ($b) {
echo $x . $b;
};
$f($a); // prints a1b1
// now let's change values of $a and $b
$a = "a2";
$b = "b2"; //--> won't be used as $b was 'b1' when declaring the function.
$f($a); // prints a2b1
?>
The use allows to import variables from the parent scope into the closure scope.
It will allow the function get() to call your closure with the appropriate param $blogPosts imported from the parent scope.

How to bind make Currying with PHP? (like Function.prototype.bind do in javascript)?

i want https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/Function/bind#Currying in PHP:
$x = function ($a, $b) {
echo $a . ' ' . $b;
};
for ($i= 0;$i< 10;$i++) {
$y = bind($x, $i)// how?
$y($i);
}
Actual currying is maybe a bit of a stretch for PHP (;-)), nonetheless you can do stuff like this with Closures in PHP 5.3+:
function populatedList() {
$args = func_get_args();
return function () use ($args) {
$localArgs = func_get_args();
return array_merge($args, $localArgs);
};
}
$sevenList = populatedList(7, 14, 21);
var_dump($sevenList('foo', 'bar', 'baz'));
// Array
// (
// [0] => 7
// [1] => 14
// [2] => 21
// [3] => foo
// [4] => bar
// [5] => baz
// )
Perhaps Anonymous functions are what you are looking for?
Example:
<?php
$greet = function($name)
{
printf("Hello %s\r\n", $name);
};
$greet('World');
$greet('PHP');
?>
The functional-php library has a class for currying (from the Docs):
Since PHP allows for optional parameters, you can decide if you want to curry them or not. The default is to not curry them.
use function Functional\curry;
function add($a, $b, $c = 10) {
return $a + $b + $c;
}
// Curry only required parameters, the default, $c will always be 10
$curriedAdd = curry('add', true);
// This time, 3 parameters will be curried.
$curriedAddWithOptional = curry('add', false);
Starting with PHP7 and the implementation of the "Uniform variable syntax", you can greatly simpliy the usage of curried functions.
use function Functional\curry;
function add($a, $b, $c, $d) {
return $a + $b + $c + $d;
}
$curriedAdd = curry('add');
$curriedAdd(10)(5)(27)(10); // -> 52
Since php5.3 you can use the "use" keyword to pass the curried argument to the scope of the returned function:
$add = function ($a) {
return function ($b) use ($a) {
return $b + $a;
};
};
var_dump($add(2)(3)); // int (5)

Help with optimising calls to the usort function in PHP

This is my callback for my usort()
public function sortProperties($a, $b) {
$sortA = inflector::camelize(str_replace('-', '_', $this->sortBy));
$sortB = inflector::camelize(str_replace('-', '_', $this->sortBy));
$a = Arr::get($a, $sortA);
$b = Arr::get($b, $sortB);
if (is_numeric($a) AND is_numeric($b)) {
return $a < $b;
} else {
return strcasecmp($a, $b);
}
}
Usually, when I see the first 2 lines in any of my code, it screams to me: refactor! I guess it's because they are identical.
I know I could make a function getCamelized(), but I don't think I'd use it again outside of this.
Is there a way to turn those 4 lines into 2? Could func_get_args() or array_walk() help me here?
Also, is there anything wrong about this sorting function?
Is there a way to turn those 4 lines
into 2?
$sortA = $sortB = inflector::camelize(str_replace('-', '_', $this->sortBy));
And for other two lines:
list($a, $b) = array(Arr::get($a, $sortA), Arr::get($b, $sortB));
As for sort, it seems to be fine at least to me.
$sortA == $sortB so that part is just duplication. Calculate $sortA once wherever you set $this->sortBy. The Arr::get lines you're stuck with. The return $a < $b; seems wrong, you should be returning a -ve, 0, +ve number.
...
function setSortBy($sortBy) {
$this->sortBy = $sortBy;
$this->sortByCam = inflector::camelize(str_replace('-', '_', $sortBy));
}
....
public function sortProperties($a, $b) {
$a = Arr::get($a, $this->sortByCam);
$b = Arr::get($b, $this->sortByCam);
if (is_numeric($a) && is_numeric($b)) {
return $a - $b;
} else {
return strcasecmp($a, $b);
}
}
Something like that. The main idea to get the camelizing part out of the loop.
Be aware that strcasecmp will return an int (1, 0, or -1) and < will return a boolean. You really need to be using one or the other. Also note that strnatcasecmp will probably give you the behavior you want for both numbers and strings so try this one:
public function sortProperties($a, $b) {
$aInflected = Arr::get($a, $sort = inflector::camelize(str_replace('-', '_', $this->sortBy)));
return strcasecmp($aInflected, Arr::get($b, $sort));
}

Sort Object in PHP [duplicate]

This question already has answers here:
Sort array of objects by one property
(23 answers)
Closed 3 months ago.
What is an elegant way to sort objects in PHP? I would love to accomplish something similar to this.
$sortedObjectArary = sort($unsortedObjectArray, $Object->weight);
Basically specify the array I want to sort as well as the field I want to sort on. I looked into multidimensional array sorting and there might be something useful there, but I don't see anything elegant or obvious.
Almost verbatim from the manual:
function compare_weights($a, $b) {
if($a->weight == $b->weight) {
return 0;
}
return ($a->weight < $b->weight) ? -1 : 1;
}
usort($unsortedObjectArray, 'compare_weights');
If you want objects to be able to sort themselves, see example 3 here: http://php.net/usort
For php >= 5.3
function osort(&$array, $prop)
{
usort($array, function($a, $b) use ($prop) {
return $a->$prop > $b->$prop ? 1 : -1;
});
}
Note that this uses Anonymous functions / closures. Might find reviewing the php docs on that useful.
You can even build the sorting behavior into the class you're sorting, if you want that level of control
class thingy
{
public $prop1;
public $prop2;
static $sortKey;
public function __construct( $prop1, $prop2 )
{
$this->prop1 = $prop1;
$this->prop2 = $prop2;
}
public static function sorter( $a, $b )
{
return strcasecmp( $a->{self::$sortKey}, $b->{self::$sortKey} );
}
public static function sortByProp( &$collection, $prop )
{
self::$sortKey = $prop;
usort( $collection, array( __CLASS__, 'sorter' ) );
}
}
$thingies = array(
new thingy( 'red', 'blue' )
, new thingy( 'apple', 'orange' )
, new thingy( 'black', 'white' )
, new thingy( 'democrat', 'republican' )
);
print_r( $thingies );
thingy::sortByProp( $thingies, 'prop1' );
print_r( $thingies );
thingy::sortByProp( $thingies, 'prop2' );
print_r( $thingies );
For that compare function, you can just do:
function cmp( $a, $b )
{
return $b->weight - $a->weight;
}
The usort function (http://uk.php.net/manual/en/function.usort.php) is your friend. Something like...
function objectWeightSort($lhs, $rhs)
{
if ($lhs->weight == $rhs->weight)
return 0;
if ($lhs->weight > $rhs->weight)
return 1;
return -1;
}
usort($unsortedObjectArray, "objectWeightSort");
Note that any array keys will be lost.
You could use the usort() function and make your own comparison function.
$sortedObjectArray = usort($unsortedObjectArray, 'sort_by_weight');
function sort_by_weight($a, $b) {
if ($a->weight == $b->weight) {
return 0;
} else if ($a->weight < $b->weight) {
return -1;
} else {
return 1;
}
}
Depending on the problem you are trying to solve, you may also find the SPL interfaces useful. For example, implementing the ArrayAccess interface would allow you to access your class like an array. Also, implementing the SeekableIterator interface would let you loop through your object just like an array. This way you could sort your object just as if it were a simple array, having full control over the values it returns for a given key.
For more details:
Zend Article
PHPriot Article
PHP Manual
function PHPArrayObjectSorter($array,$sortBy,$direction='asc')
{
$sortedArray=array();
$tmpArray=array();
foreach($this->$array as $obj)
{
$tmpArray[]=$obj->$sortBy;
}
if($direction=='asc'){
asort($tmpArray);
}else{
arsort($tmpArray);
}
foreach($tmpArray as $k=>$tmp){
$sortedArray[]=$array[$k];
}
return $sortedArray;
}
e.g =>
$myAscSortedArrayObject=PHPArrayObjectSorter($unsortedarray,$totalMarks,'asc');
$myDescSortedArrayObject=PHPArrayObjectSorter($unsortedarray,$totalMarks,'desc');
You can have almost the same code as you posted with sorted function from Nspl:
use function \nspl\a\sorted;
use function \nspl\op\propertyGetter;
use function \nspl\op\methodCaller;
// Sort by property value
$sortedByWeight = sorted($objects, propertyGetter('weight'));
// Or sort by result of method call
$sortedByWeight = sorted($objects, methodCaller('getWeight'));
Update from 2022 - sort array of objects:
usort($array, fn(object $a, object $b): int => $a->weight <=> $b->weight);
Full example:
$array = [
(object) ['weight' => 5],
(object) ['weight' => 10],
(object) ['weight' => 1],
];
usort($array, fn(object $a, object $b): int => $a->weight <=> $b->weight);
// Now, $array is sorted by objects' weight.
// display example :
echo json_encode($array);
Output:
[{"weight":1},{"weight":5},{"weight":10}]
Documentation links:
usort
spaceship operator (PHP 7.0)
scalar type declaration (PHP 7.0)
return type declaration (PHP 7.0)
arrow function (PHP 7.4)
If you want to explore the full (terrifying) extent of lambda style functions in PHP, see:
http://docs.php.net/manual/en/function.create-function.php

Categories