How to reduce indentation level in given PHP code snippet - php

How to refactor this snippet of code, to reduce indentation level by one?
I just wonder is it possible in PHP to write this code in a diffrent way, with just one level of indentation.
The code:
private function isArrayMatchingCriteria(array $array) {
foreach($array as $element) {
if (! $this->isElementMatchingCriteria($element) {
return false;
}
}
return true;
}
Please take into consideration, that:
this code doesn't always iterate over all array elements - so combination of count + array_filter / array_map isn't the same
it is easy to do by introducing a dedicated object attribute serving as a flag, but I'm looking for a way without introducing new attributes

If you're just looking to remove indentation, you could use:
private function isArrayMatchingCriteria(array $array) {
foreach($array as $element) {
if (!$this->isElementMatchingCriteria($element)) return false;
}
return true;
}

Use array_map, something like this:
class MyClass
{
private function isElementMatchingCriteria( $element )
{
// DUMMY, replace with actual code
if ( $element == "foo" || $element == "bar" ) {
return true;
} else {
return false;
}
} // end is Element Matching Criteria
public function isArrayMatchingCriteria(array $array)
{
$results = array_map( array( $this, "isElementMatchingCriteria"), $array );
$isMatch = true;
foreach ( $results as $result ) {
$isMatch = $isMatch && $result;
} // end foreach
return $isMatch;
} // end function isArrayMatchingCriteria
} // end MyClass
$myClass = new MyClass();
$array = array( "foo", "bar", "baz" );
$result = $myClass->isArrayMatchingCriteria( $array );
print_r( $result );

Related

Recursion on subarrays with "child" key

I have array of arrays - tree structure of main menu.
I try to find in this tree one node with needed slug and return this node with all it's childs.
I write little recurcive function
<?php
$tree = '[{"id":1,"structure":1,"parent":0,"slug":"medicinskaya-ge","child":{"2":{"id":2,"structure":1.1,"parent":1,"slug":"dnk-diagnostika","child":{"3":{"id":3,"structure":"1.1.1","parent":2,"slug":"dnk-diagnostika","datafile":"ssz","template":"ssz"},"4":{"id":4,"structure":"1.1.2","parent":2,"slug":"dnk-diagnostika","child":{"5":{"id":5,"structure":"1.1.2.1","parent":4,"slug":"dnk-diagnostika"},"6":{"id":6,"structure":"1.1.2.2","parent":4,"slug":"testirovanie-ge"},"7":{"id":7,"structure":"1.1.2.3","parent":4,"slug":"dnk-diagnostika"}}},"8":{"id":8,"structure":"1.1.3","parent":2,"slug":"dnk-diagnostika"},"9":{"id":9,"structure":"1.1.4","parent":2,"slug":"texnologiya-kol"}}}}}]';
$tree = json_decode($tree, true);
function getSlugData(string $slug, array $data)
{
foreach ($data as $row) {
if ($row['slug'] == $slug) {
return $row;
}
if (isset($row['child'])) {
//return $this->getSlugData($slug, $row['child']);
}
}
return [];
}
$result = getSlugData('testirovanie-ge', $tree);
print_r($result);
But as a result I have an empty array. If I print_r($row) when $row['slug'] == $slug - It appears on screen.
if ($row['slug'] == $slug) {
exit(print_r($row));
return $row;
}
What's my mistake?
In programming, recursion is a useful and powerful mechanism that allows a function to call itself directly or indirectly, that is, a function is said to be recursive if it contains at least one explicit or implicit call to itself.
I modified your code a bit and got the solution below.
$tree = '[{"id":1,"structure":1,"parent":0,"slug":"medicinskaya-ge","child":{"2":{"id":2,"structure":1.1,"parent":1,"slug":"dnk-diagnostika","child":{"3":{"id":3,"structure":"1.1.1","parent":2,"slug":"dnk-diagnostika","datafile":"ssz","template":"ssz"},"4":{"id":4,"structure":"1.1.2","parent":2,"slug":"dnk-diagnostika","child":{"5":{"id":5,"structure":"1.1.2.1","parent":4,"slug":"dnk-diagnostika"},"6":{"id":6,"structure":"1.1.2.2","parent":4,"slug":"testirovanie-ge"},"7":{"id":7,"structure":"1.1.2.3","parent":4,"slug":"dnk-diagnostika"}}},"8":{"id":8,"structure":"1.1.3","parent":2,"slug":"dnk-diagnostika"},"9":{"id":9,"structure":"1.1.4","parent":2,"slug":"texnologiya-kol"}}}}}]';
$tree = json_decode($tree, true);
//print_r($tree);
//die();
function getSlugData(string $slug, array $data, string $key = 'slug')
{
$result = [];
foreach ($data as $row) {
// Checks if the key exists and is the desired value for that key in the array
if (isset($row[$key]) && $row[$key] === $slug) {
return $row;
}
// If it is an array, apply recursion by calling getSlugData again
if (is_array($row)) {
$result = getSlugData($slug, $row, $key);
if ($result !== []) {
return $result;
}
}
}
return $result;
}
print_r(getSlugData('testirovanie-ge', $tree));
print_r(getSlugData('texnologiya-kol', $tree));
print_r(getSlugData('nothing-here', $tree));
die();
In the recursive function, you must not break the loop early unless you find your slug match. If a non-slug-match has a child element, you must iterate it and potentially pass up a match in subsequent recursive calls.
Code: (Demo)
function getSlugData(string $slug, array $data): array
{
foreach ($data as $row) {
if ($row['slug'] === $slug) {
return $row;
}
if (isset($row['child'])) {
$deeper = getSlugData($slug, $row['child']);
if ($deeper) {
return $deeper;
}
}
}
return [];
}
P.s. you aren't calling a class method, so $this-> is inappropriate.

_.findWhere() in PHP?

What is the php implementation of underscore's _.findWhere({key:'val'})?
This is how the method is documented by Underscorejs.org:
_.findWhere(list, properties)
Looks through the list and returns the first value that matches all of the key-value pairs listed in properties.
I wrote these little functions. Might be handy.
function where($list, $props)
{
$result = array_filter(
$list,
function ($e) use ($props)
{
$count = 0;
foreach ($props as $key => $value)
{
if ($value == $e[$key])
{
$count += 1;
}
return $count == count($props);
}
}
);
return $result;
}
function findWhere($list, $props)
{
$result = where($list, $props);
return array_values($result)[0];
}
There is none. Underscore is a collection of functions written in JS. It has nothing to do with PHP.

PHP Function Argument to an array

Can you do something crazy like this
function cool_function($pizza, $ice_cream) {
make the arguments in the array into an array
return $array_of_paramaters // my new array
} // end function
print_r(cool_function); // outputs array(0 => pizza, 1=> ice cream)
Actually, this is pretty easy (and read the manual: func_get_args — Returns an array containing a function's argument list, see as well: Variable-length argument lists):
function cool_function($pizza, $ice_cream) {
return func_get_args();
}
but as asked in comments, why do you need this?
Or do you need the variable names? Reflection Docs is your friend:
function cool_named($neutron, $electron)
{
$f = new ReflectionFunction(__FUNCTION__);
$p = array();
foreach($f->getParameters() as $p1)
$p[] = '$'.$p1->name;
return $p;
}
var_dump(cool_named());
Or just both? (Edit: taking under-length, optional and over-length parameters into account):
function overall($neutron, $electron, $quark = 'xiaro')
{
$f = new ReflectionFunction(__FUNCTION__);
$defined = $f->getParameters();
$passed = func_get_args() + array_fill(0, count($defined), NULL);
foreach($defined as &$param)
$param = '$'.$param->name;
return array_combine($defined + array_keys($passed), $passed);
}
var_dump(overall('clara', 'peter', 'moon', 'jupiter'));
I'm not sure if you're looking for func_get_args which return all arguments passed to a function, or the ReflectionFunction class.
A basic example of func_get_args:
function cool_function($pizza, $ice_cream) {
return func_get_args();
}
But you don't need the arguments to make this work:
function cool_function() {
return func_get_args();
}
// cool_function(1,2,3) will return array(1,2,3)
The reflection option:
/**
* Returns an array of the names of this function
*/
function getMyArgNames($a,$b,$c)
{
$args = array();
$refFunc = new ReflectionFunction(__FUNCTION__);
foreach( $refFunc->getParameters() as $param ){
$args[] = $param->name;
}
return $args;
}
Or, for the really crazy:
/**
* Returns an associative array of the names of this function mapped
* to their values
*/
function getMyArgNames($a,$b,$c)
{
$received = func_get_args();
$i = 0;
$args = array();
$refFunc = new ReflectionFunction(__FUNCTION__);
foreach( $refFunc->getParameters() as $param ){
$args[$param->name] = $received[$i++];
}
// include all of those random, optional arguments.
while($i < count($received)) $args[] = $received[$i++];
return $args;
}
do you mean
function valuesToArray($value1,$value2){return array($value1,$value2);}
If I got you right, you so it like this:
function cool_function($pizza, $ice_cream) {
return array($pizza, $ice_cream);
}
but you could simply do that:
$new_var = array($pizza, $ice_cream);

Use Array From Function 1 in Function 2

I have a (simplified) function that uses in_array() to check if a value is in an array:
function is($input) {
$class = array('msie','ie','ie9');
$is = FALSE;
if (in_array($input, $class)) {$is = TRUE;}
return $is;
}
if (is('msie'))
echo 'Friends don\'t let friends use IE.';
I want to break this into two separate functions, where the first defines the array:
function myarray() {
$class = array('msie','ie','ie9');
}
and the second runs the check—either like this:
function is($input) {
myarray();
$is = FALSE;
if (in_array($input, $class)) {$is = TRUE;}
return $is;
}
Or this:
function is($input) {
global $class;
$is = FALSE;
if (in_array($input, $class)) {$is = TRUE;}
return $is;
}
But both of the above cause this error:
Warning: in_array() [function.in-array]: Wrong datatype for second argument in /home/vanetten/temp.ryanve.com/PHP/airve.php on line 73
What is the proper way use an array from one function in another? Can an array be a global variable? How do I make this work? Is it more efficient to use a global variable or to call the first function within the second function. Any help is definitely appreciated.
Return the array from the first function:
function myarray() {
return array('msie','ie','ie9');
}
function is($input) {
$array = myarray();
return in_array($input, $array);
// or even just
// return in_array($input, myarray());
}
function is($input) {
$class = myarray();
$is = false;
...
Easiest way (which also negates the use of global variables, which is a bad practice since using $class somewhere else down the line may result in unexpected behavior) is something like
function myarray() {
return array('msie','ie','ie9');
}
function is($input) {
$array = myarray();
$is = FALSE;
if (in_array($input, $array)) {$is = TRUE;}
return $is;
}
if (is('msie'))
echo 'Friends don\'t let friends use IE.';
In this example, we just make myarray() return the needed array. In is(), add the line $array = myarray(), which will save the array from myarray(), so it is useable from is() as the alias $array. Then simply change $class to $array, and it should work fine.

Is an 'invoke'-style callback possible in PHP5?

PHP functions such as 'array_map' take a callback, which can be a simple function or a class or object method:
$array2 = array_map('myFunc', $array);
or
$array2 = array_map(array($object, 'myMethod'), $array);
But is there a syntax to pass a method which is bound within the iteration to the current object (like 'invoke' in Prototype.js)? So that the following could be used:
$array2 = array_map('myMethod', $array);
with the effect of
foreach($array as $obj) $array2[] = $obj->myMethod();
Obviously I can use this form, or I can write a wrapper function to make the call, and even do that inline. But since 'myMethod' is already a method it seems to be going round the houses to have to do one of these.
Not currently. When php 5.3 comes out, you could use the following syntax:
$array2 = array_map(function($obj) { return $obj->myMethod(); }, $array);
function obj_array_map($method, $arr_of_objects) {
$out = array();
$args = array_slice(func_get_args(), 2);
foreach ($arr_of_objects as $key => $obj) {
$out[$key] = call_user_func_array(Array($obj, $method), $args);
}
return $out;
}
// this code
$a = Array($obj1, $obj2);
obj_array_map('method', $a, 1, 2, 3);
// results in the calls:
$obj1->method(1, 2, 3);
$obj2->method(1, 2, 3);
Basically, no. There is no special syntax to make this any easier.
I can think of a fancier way of doing this in PHP 5.3, seeing as there's always more than one way to do things in PHP, but I'd say it wouldn't necessarily be better than your foreach example:
$x = array_reduce(
$array_of_objects,
function($val, $obj) { $val = array_merge($val, $obj->myMethod()); return $val; },
array()
);
Just go with your foreach :)
<?php
// $obj->$method(); works, where $method is a string containing the name of the
// real method
function array_map_obj($method, $array) {
$out = array();
foreach ($array as $key => $obj)
$out[$key] = $obj->$method();
return $out;
}
// seems to work ...
class Foo {
private $y = 0;
public function __construct($x) {
$this->y = $x;
}
public function bar() {
return $this->y*2;
}
}
$objs = array();
for ($i=0; $i<20; $i++)
$objs[] = new Foo($i);
$res = array_map_obj('bar', $objs);
var_dump($res);
?>
voila!
This is a bit of a silly answer, but you could subclass ArrayObject and use that instead of a normal array:
<?php
class ArrayTest extends ArrayObject {
public function invokeMethod() {
$result = array();
$args = func_get_args();
$method = array_shift($args);
foreach ($this as $obj) {
$result[] = call_user_func_array(array($obj, $method), $args);
}
return $result;
}
}
//example class to use
class a {
private $a;
public function __construct($a) {
$this->a = $a;
}
public function multiply($n) {
return $this->a * $n;
}
}
//use ArrayTest instance instead of array
$array = new ArrayTest();
$array[] = new a(1);
$array[] = new a(2);
$array[] = new a(3);
print_r($array->invokeMethod('multiply', 2));
Outputs this:
Array
(
[0] => 2
[1] => 4
[2] => 6
)
I would use create_function() to ... well ... create a temporary function for array_map while waiting for PHP 5.3
$func = create_function('$o', '$o->myMethod();');
array_map($func, $objects);

Categories