I have code like this:
$finalResult = true;
$finalResult = $finalResult && function_01();
// some code here
$finalResult = $finalResult && function_02();
// some many lines of code here
$finalResult = $finalResult && function_XX();
And I'm looking for a way how to shorten the code (just for a human-readibility reasons) to something like:
$finalResult = true;
$finalResult &&= function_01();
// some code here
$finalResult &&= function_02();
// some many lines of code here
$finalResult &&= function_XX();
But of course this doesn't work and operator &= is not for boolean values, but for binary.
How should I do this ?
Thanks.
$names = array('function01','function02'...);
$result = true;
foreach($names as $caller)
{
$result = $result && $caller();
}
otherwise instead of $caller() you could look for call_user_func ( http://us3.php.net/call_user_func )
it's not really fantastic, but it's shorter :/ not a big deal
edit:
uhm... i guess that after your edit this solution is not more functional... should i delete it ?
I would also reconsider the logic of your code by adding a class that makes these checks: if all the checking logic is in a class whose purpose is just that you could surely benefit of readability
Stormsson's but improved - finish as soon as you know the result:
$names = array( 'function01','function02'... );
$result = true;
foreach( $names as $caller )
{
if ( $result == false ) break; // short circuit
$ret = $caller()
if ( $ret == false )
{
$result = false;
break; // short circuit
}
$result = $result && $ret;
}
OK, after all it seems I will not get it any simpler than original.
For those of you who don't understand why I want to have it in some "short" form - only reason was to have it shorter and nicer. Just the same reason why there is possibility to write $a += 3 just for beauty.
Anyway, thanks to everybody :)
Related
I have some bad programming habits caused by ocd, but let's not discuss my obsessive compulsive disorder while programming (although this post reinforces it, omg).
I have these two pieces of code (time to execute 2.1934509277344E-5):
function get_paths($string, $array) {
$result = array();
foreach($array as $i)
if (stripos($i, $string) !== false)
$result[] = $i;
return empty($result) ? false : $result;
}
The return statement looks inverted, with the negative result coming first (my formalist folks would go crazy). I know, I know, I could add a negation, but it looks worst. To avoid this I came up with the following solution (time to execute 2.288818359375E-5):
function get_paths($string, $array) {
$result = null;
foreach($array as $i)
if (stripos($i, $string) !== false)
(array)$result[] = $i;
return isset($result) ? $result : false;
}
This piece of code involves the cast (array)$result[] = $i;. The point is: how dumb is it to cast an array to an array everytime? Do someone have some in depth information about casting to the same type in php?
If it matters so much to you:
function get_paths($string, $array) {
$result = array();
foreach($array as $i)
if (stripos($i, $string) !== false)
$result[] = $i;
return count($result) > 0 ? $result : false;
}
I've a sequence of if statements and I can't figure a better way to write it here's it is :
$a='';$b='';$c='';
if($row->nA!=0){
$a = $row->nA;
}
if($row->nB!=0){
$b = $row->nB;
}
if($row->nC!=0){
$b = $row->nC;
}
It simple but I can't find how write it better than this
There's nothing completly wrong with your way.
If you want to write something else, try it like this:
$a = ($row->nA != 0) ? $row-nA : '';
$b = ($row->nB != 0) ? $row-nB : '';
$c = ($row->nC != 0) ? $row-nC : '';
But, like i said, there is nothing wrong with your way ;)
Sascha Presnac is right - there is nothing wrong with the way you're doing it. However, it might be useful if you tidy up your code a little.
$a = '';
$b = '';
$c = '';
if ($row->nA != 0) {
$a = $row->nA;
}
if ($row->nB != 0) {
$b = $row->nB;
}
if ($row->nC != 0) {
$b = $row->nC;
}
Using extra lines to write your code is not a problem. It is better to be more spread out and easily readable, than scrunched up and hard to read :). But if you want to do it in as few a lines as possible then go for Sacha Presnac's approach :)
If you have yo do it for a lot of variables you could do it with
$variables = ['a', 'b', 'c'];
foreach ($variables as $variable)
{
$$variable = ($row->{"n" . strtoupper($variable)} != 0) ? $row->{"n" . strtoupper($variable)} : '';
}
I need to identify every instance where a value in one array (needle) occurs in another array (haystack). in_array() seems to be my best option, and the code below works perfectly until I need to use it on rows fetched from a db - it keeps appending values instead of setting them each time it's called.
While I can't actually use unset() in this situation, I was surprised to discover that even that didn't seem to resolve the problem.
UPDATE - Example of what's being returned
I temporarily changed the db values so that $needles has only value per row (in order to make it possible to sort through the values filling up my screen ;-))
False;
False; False; True;
False; False; True; False; True;
False; False; True; False; True; False; True;
False; False; True; False; True; False; True; False;
This works correctly
(I've posted a functional example here)
$needles = array('John', 'Alex');
$haystack = array('John','Alexander','Kim', 'Michael');
foreach ($needles as $needle) {
if (in_array($needle, $haystack) ) {
$Match = 'True';
}
else {
$Match = 'False';
}
}
This keeps appending values - Edited to reflect the code I'm using
$Customer_Categories_Arr = array('Casual','Trendy');
if ($stmt->columnCount()) {
while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$Product_Categories_Arr[]=$row["Taste_Category"];
// Use when column contains CSV
// $Product_Categories_Arrx = explode(',', trim($Product_Categories_Arr[0]));
foreach ($Product_Categories_Arr as $Product_Category_Arr) {
if (in_array($Product_Category_Arr, $Customer_Categories_Arr)){
$Matches_Product_Category = "True";
} else {
$Matches_Product_Category = "False";
}
echo $Product_Category_Arr, ', ', $Matches_Product_Category, '; ';
}
}
}
It is not really clear what you are trying to do. But maybe this would help:
$customerCategories = array('Casual', 'Trendy');
if( $stmt->columnCount() ){
while( $row = $stmt->fetch( PDO::FETCH_ASSOC )){
$productCategoryRow = $row[ 'Taste_Category' ];
// If it is not working, try uncommenting the next line
// $productCategories = [];
$productCategories = explode( ',', trim( $productCategoryRow ));
$match = "False";
foreach( $productCategories as $productCategory ){
if( in_array( $productCategory, $customerCategories )){
$match = "True";
}
echo $match . ";";
}
}
}
This prints your result on the screen every time a loop is done. Is this what you mean?
If you want the second block of code to do what the first block of code (which works correctly) does, then the second block should look like this -
if ($stmt->columnCount()) {
while($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
$needle =$row["product_var"];
$Match = "False";
if (in_array($needle, $haystack)){
$Match = "True";
}
}
}
You don't need do use the foreach because that is replaced by the while loop in the second block.
I am going to try an solve this. I think the problem is with:
$needles[]=$row["product_var"];
I think this should be:
$needles=$row["product_var"];
The column "product_var" contains an CSV (as you mentioned), so I can make an example like this:
$csv = "jake;john;alex;kim";
An example with brackets ($needles[]):
for($i=0; $i<5; $i++) {
$needles[] = explode(";", $csv);
echo(count($needles).", ");
}
returns:
1, 2, 3, 4, 5,
edit (for more explaining):
if I use print_r I see the array expanding, exactly how it happens in your example:
step 1: it adds an array to $needles with values ('jake','john','alex','kim')
step 2: it adds an array to $needles, so it contains 2x the values ('jake','john','alex','kim')
step 3: it adds an array to $needles, so it contains 3x the values ('jake','john','alex','kim')
etc.
Now without the brackets ($needles):
for($i=0; $i<5; $i++) {
$needles = explode(";", $csv);
echo(count($needles).", ");
}
This returns:
4, 4, 4, 4, 4,
And every time the array simply contains the values ('jake','john','alex','kim') -which is what you want.
Could this explain the "expanding values"? (or am I just doing something really stupid which has nothing to do with your problem??)
edit:
If this is what is going wrong, then you are adding to an array, instead of only using the new array from $row["product_var"] (hope this makes any sense; it seems I am pretty bad at explaining what's happening).
So, as the title says... any alternative to:
$valid_times = array('ever', 'today', 'week', 'month');
if (($this->_time == 'ever') OR ($this->_time == 'day'))
OR
if (in_array($this->_time, $valid_times))
??
Note: I know the mentioned above works, but I'm just looking for new things to learn and experiment with
UPDATE
Thanks for the info, but I didn't mentioned switch() as an alternative because it's not the case for my code. It has to be an if-statement, and I was wondering if exists something like:
if($this->_time == (('ever') OR ('day') OR ('month')))
What do you think? That would be a shorter way of the first if mentioned above
What about ?
$a1 = array("one","two","three");
$found = "two";
$notFound = "four";
if (count(array_diff($a1,array($found))) != count($a1))
/* Found */
Either you can use
$found = array("one","three");
if (count(array_diff($a1,$found)) != count($a1));
/* Either one OR three */
http://codepad.org/FvXueJkE
The only alternative I can think to accomplish this would be using regex.
$valid_times = array('ever','day','week','hour');
if(preg_match('/' . implode('|', $valid_times) . '/i', $this->_time)){
// match found
} else {
// match not found
}
[EDIT] Removed original answer since you've now specified you don't want to use switch.
In your updated question, you asked if something like this is possible:
if($this->_time == (('ever') OR ('day') OR ('month')))
The direct answer is 'no, not in PHP'. The closest you'll get is in_array(), with the array values in place in the same line of code:
if(in_array($this->_time, array('ever','day','month'))
PHP 5.4 has an update allows for shorter array syntax, which means you can drop the word array, which makes it slightly more readable:
if(in_array($this->_time, ['ever','day','month'])
But it is still an in_array() call. You can't get around that.
Sometime like this for in_array?
$arr = array(1, 2, 'test');
$myVar = 2;
function my_in_array($val, $arr){
foreach($arr as $arrVal){
if($arrVal == $val){
return true;
}
}
return false;
}
if(my_in_array($myVar, $arr)){
echo 'Found!';
}
Convoluted, but it is an alternative
$input = 'day';
$validValues = array('ever','day');
$result = array_reduce($validValues,
function($retVal,$testValue) use($input) {
return $retVal || ($testValue == $input);
},
FALSE
);
var_dump($result);
You could also use the switch statement.
switch ($this->_time) {
case 'ever':
case 'day':
//code
break;
default:
//something else
}
For the sake of science, it turns out you can use yield in a ternary operator, so you could put some complex evaluations in a anonymous generator, and have it yield on the first one that evaluates to true, without needing to evaluate them all:
$time = 'today';
if( (function()use($time){
$time == 'ever' ? yield true:null;
$time == 'today' ? yield true:null;
$time == 't'.'o'.'d'.'a'.'y' ? yield true:null;
})()->current() ){
echo 'valid';
}
In this case it will echo 'valid' without ever evaluating the concatenation.
Currently my mind is under heavy pressure and I can't stay a long time focusing on one single issue, I am pretty sure that the way I made it is basic and can be improved to make it smaller and easier (more professional maybe ?) code;
<?php
$intro_id = rand(1,2);
if($intro_id == 1 && !empty($options['hidden_intro_one'])){
$hidden_intro = $options['hidden_intro_one'];
}
elseif(!empty($options['hidden_intro_two'])){
$hidden_intro = $options['hidden_intro_two'];
}
else{
//back to circle number 1
$hidden_intro = $options['hidden_intro_one'];
}
?>
Partially SOLVED :
the solution was to use array_rand() function like this :
<?php
$random_intro = array($options['hidden_intro_one'],$options['hidden_intro_two']);
$hidden_intro = $random_intro[array_rand($random_intro)];
?>
But if one of the intros is left empty, it will appear empty when you echo the code, while I want to print the other intro (if not empty) instead...
It can certainly be 'improved'. Code can always be improved :) One easy improvement you can always do (more of a habit to teach yourself) is to add a comment about what the code is supposed to do.
Anyway, what (I think) you're trying to do is basically the same as:
$hidden_intro = $options[ array_rand( $options ) ];
<?php
$intros = array(
1 => $options['hidden_intro_one'],
2 => $options['hidden_intro_two']
);
$intro_id = rand(1,2);
$hidden_intro = empty($intros[$intro_id]) ? reset($intros) : $intros[$intro_id];
?>
Although I don't like using reset() as a way to get the first possible value, but you can customize the 'default' value process :)
Something like this maybe:
$intro = array("hidden_intro_one","hidden_intro_two");
$hidden_intro = $options[array_rand($intro)];
Or, if $options only contains hidden_intro_one and hidden_intro_two you could just do:
$hidden_intro = array_rand($options);
EDIT oops, this leaves out the part where it can't be empty.
If $options only contains hidden_intro_one and hidden_intro_two
$hidden_intro = $options["hidden_intro_one"]; // fallback if both are empty
shuffle($options);
foreach($options as $option)
if(!empty($option)){
$hidden_intro = $option;
break;
}
Else
$hidden_intro = $options["hidden_intro_one"]; // fallback if both are empty
$intros = array("hidden_intro_one","hidden_intro_two");
shuffle($intros);
foreach($intros as $intro)
if(!empty($options[$intro])){
$hidden_intro = $options[$intro];
break;
}
This might not necessarily be better though, but it will be if you add more values.
Encapsulate what varies and for the standard problem use an existing function like array_rand:
$intros = get_non_empty_intros_from_options($options);
$hidden_intro = array_rand($intros);
function get_non_empty_intros_from_options($options)
{
$intro_option_keys = array('one', 'two');
$intro_option_key_mask = 'hidden_intro_%s';
$intros = array();
foreach ($intro_option_keys as $intro)
{
$key = sprintf($intro_option_key_mask, $intro);
if (empty($options[$key]))
continue
;
$intros[$key] = $options[$key];
}
return $intros;
}
This method will allow you to use more than one intro.
<?php
//why not make your intro's an array in your options array
$options['hidden_intro'] = array('one', 'two');
//declare your intro variable
$hidden_intro;
//now lets loop our intro's
foreach($options['hidden_intro'] as $intro)
{
if(!empty($intro))
{
$hidden_intro = $into;
break;
}
}
if(isset($hidden_intro))
{
//use your intro here
}
?>
Just for fun, an (almost) oneliner:
$to_be_choosen_keys = array("hidden_intro_one","hidden_intro_two");
$hidden_intro = array_rand(
array_intersect_key(
$options,
array_flip($to_be_choosen_keys)
)
);