define variable within conditional whilst testing against in php - php

Is it possible to call a method within a conditional to test against but also store return in a var within the same conditional reducing the api calls?
ie something like this:
elseif(
($auth_type = \proj101\user::getUserAuthType( $user_profile['email'] ) )
&& $auth_type != AUTH_TYPE_GOOGLE
){
//$auth_type now equals the function return and not just 'true'

Yeah, you can do that, you just have to get the order of operations right. Since assignment has lower precedence than logical &&, you end up setting auth_type to the result of the && operation.
Consider this simple example:
<?php
const AUTH_TYPE_GOOGLE = 1;
function userAuthTypeStub( $x ){
return 2;
}
if( 0 ){
// who knows what to do?
}
elseif(
$auth_type = userAuthTypeStub( 0 )
&& $auth_type != AUTH_TYPE_GOOGLE
){
echo "$auth_type\n" . userAuthTypeStub(0) . "\n";
}
you get
1
2
but if you fix the order of operations, you get what you expect:
<?php
const AUTH_TYPE_GOOGLE = 1;
function userAuthTypeStub( $x ){
return 2;
}
if( 0 ){
// who knows what to do?
}
elseif(
( $auth_type = userAuthTypeStub( 0 ) )
&& ( $auth_type != AUTH_TYPE_GOOGLE )
){
echo "$auth_type\n" . userAuthTypeStub(0) . "\n";
}
2
2
Note I had to adjust the result of the function in both cases, because if $auth_type ends up being 0 in either case, the elseif evaluates to false and the output is never executed. That's one of the reasons I agree with most of the criticisms being offered that it would make the most sense to set $auth_type and then test its value.
Some languages (namely: C, if I'm not mistaken) don't promise anything about the order of operations of both sides of a logical &&, so it may be safe to say that depending on the second from the first is a bad practice. I think that may be for the optimizations possibly gained by reversing the order. This certainly isn't C so maybe it doesn't matter, but it sure makes debugging harder!
http://www.php.net/manual/en/language.operators.precedence.php

Related

Why is not possible to decode and unserialize in the same line? (like this example)

Why this is not possible?
$b64_encoded = base64_encode(serialize(array('test')));
if( $b64_decoded = base64_decode($b64_encoded) && $unserialized = unserialize($b64_decoded) )
{
var_dump($unserialized);
}
You can.
What's happened is that PHP sees $b64_decoded as an undefined and unset variable because you've got it tied up in your if statement without correctly parting it.
See this:
if( $b64_decoded = base64_decode($b64_encoded) && $unserialized = unserialize($b64_decoded) )
PHP believes the && has a higher priority over =. Your code effectivly is;
$b64_decoded = (base64_decode($b64_encoded) && $unserialized) = unserialize($b64_decoded)
Which doesn't seem to make any logical sense.
So, we have to tell PHP the priority of the operations and what items are grouped together. We can do this by wrapping our statement with ( )
Such as this:
if( ($b64_decoded = base64_decode($b64_encoded)) && $unserialized = unserialize($b64_decoded) )
^ ^
PHP now understands the priority of the statement as you have specified.

multiple !isset() with OR conditions in php

if(!isset($_GET['new_quiz']) || !isset($_GET['view_quiz']) || !isset($_GET['alter_quiz'])){
echo "No";
}
else{ echo "Yes"; }
When I go to index.php?view_quiz, it should give result as Yes, but it results as No. Why?
My Other Tries:
(!isset($_GET['new_quiz'] || $_GET['view_quiz'] || $_GET['alter_quiz']))
( ! ) Fatal error: Cannot use isset() on the result of an expression
(you can use "null !== expression" instead) in
C:\wamp\www\jainvidhya\subdomains\teacher\quiz.php on line 94
(!isset($_GET['new_quiz'],$_GET['view_quiz'],$_GET['alter_quiz']))
NO
You may find than inverting the logic makes the code easier to read, I also like to have a more positive idea of conditions as it can read easier (rather than several nots means no).
So this says if anyone of the items isset() then the answer is Yes...
if(isset($_GET['new_quiz']) || isset($_GET['view_quiz']) || isset($_GET['alter_quiz'])){
echo "Yes";
}
else{ echo "No"; }
Note that I've changed the Yes and No branches of the if around.
You are probably looking for
if(!isset($_GET['new_quiz']) && !isset($_GET['view_quiz']) && !isset($_GET['alter_quiz'])){
echo "No";
}
else {
echo "Yes";
}
which will print Yes if none of new_quiz, view_quiz and alter_quiz are present in the URL. If this is not your desired outcome, please elaborate on your problem.
#paran you need to set a value for view_quiz=yes for example
if(!isset($_GET['new_quiz']) || !isset($_GET['view_quiz']) || !isset($_GET['alter_quiz'])){
echo "No";
}
else{ echo "Yes"; }
and the url
index.php?new_quiz=yes
index.php?view_quiz=yes
index.php?alter_quiz=yes
All Will return true
isset()allows multiple params. If at least 1 param does not exist (or is NULL), isset() returns false. If all params exist, isset() return true.
So try this:
if( !isset( $_GET['new_quiz'], $_GET['view_quiz'], $_GET['alter_quiz']) ) {
First, to answer your question:
When I go to index.php?view_quiz, it should give result as Yes, but it results as No. Why?
This is becaue this
if(!isset($_GET['new_quiz']) || !isset($_GET['view_quiz']) || !isset($_GET['alter_quiz'])){
checks if either one of your parameter is not set, which will always be the case as long as you are not setting all three parameter simultaneously like this:
index.php?alter_quiz&view_quiz&new_quiz
As #nigel-ren stated, you may wan't to change that logic to
if(isset($_GET['new_quiz']) || isset($_GET['view_quiz']) || isset($_GET['alter_quiz'])){
echo 'Yes';
which checks if at least one parameter is set.
If you wan't to check if there is only one of the three parameters set, you would have to work with XOR (which is slightly more complicated)
$a = isset($_GET['new_quiz']);
$b = isset($_GET['view_quiz']);
$c = isset($_GET['alter_quiz']);
if( ($a xor $b xor $c) && !($a && $b && $c) ){
echo 'Yes';
(based on this answer: XOR of three values)
which would return true if one and only one of the three parameters is set.
But - and this is just an assumption, please correct me if I'm wrong - I think what you are trying to achieve are three different pages (one for creating a quiz, one for viewing it and one for editing it). Therefore, you will likely run into a problem with your current setup. For example: What would happen if a user calls the page with multiple parameters, like
index.php?alter_quiz&view_quiz
Would you show both pages? Would you ignore one parameter? I would recommend to work with a single parameter to avoid this problem in the first place. For example site which can take the values alter_quiz, view_quiz or new_quiz. E.g.:
index.php?site=alter_quiz
Then you can work like this:
// check if site is set before getting its value
$site = array_key_exists( 'site', $_GET ) ? $_GET['site'] : NULL;
// if it's not set e.g. index.php without parameters is called
if( is_null($site) ){
// show the start page or something
}else{
$allowed_sites = ['new_quiz', 'view_quiz', 'alter_quiz'];
// never trust user input, check if
// site is an allowed value
if( !in_array($site, $allowed_sites, true) ){
die('404 - This site is no available');
}
// here you can do whatever your site should do
// e.g. include another php script which contains
// your site
include('path/to/your/site-' . $site . '.php');
// or echo yes
echo 'Yes';
}

PHP Is one value set and not another

I'm working on a truthy/falsy where I need to check 2 values, of which one may be null, the other 0. If integer vs string value same, they'd be the same.
The simplest I've been able to break it down is:
if($var1 == $var2) {// They may be the same
if((isset($var1) && !isset($var2)) || (!isset($var1) && isset($var2))) { // Is one set, and not the other?
return true; // As different as we'll allow
}
return false; // Nope they're the same
}
return true; // Definitely different
My question would be mainly, given the above code block, is there a simpler way to check if one value is set, and not the other?
EDIT: The reason I check for equality first, is that the value may pass 1 == 10 or 10 == '10', in which case, I don't need to check further, but if null == 0, this would pass and require further checking. I saw that I can pass multiple values to isset, which would work if I required both to be set or both not set, but if one is, and not the other, that's where I need to flag.
Using the null coalescing operator may come in handy...
return ($var1 ?? null) !== ($var2 ?? null);
Checks that they are not equal and at least one is defined and not null.
You are checking for equality before checking if they are set.
I'd recommend checking if they are set first.
If the PURE goal is to check if one is set and not the other, then:
return ( ( empty($var1) && ! empty($var2) ) || ( ! empty($var1) && empty($var2) );
Per comments, isset is the requirement, so this version:
return ( ( isset($var1) && ! isset($var2) ) || ( ! isset($var1) && isset($var2) );
And, props to #deceze to suggest an even simpler version:
return ( isset($var1) != isset($var2) );

Using for loop within if statement in PHP

I am writing a rostering app. This statement checks that by booking an extra shift the user doesn't violate a rule whereby they have booked more than 7 night shifts in a row. This code runs fine but I am trying to find a more elegant way to write it, for instance using a for loop within the if statement. This snippet exists within a bigger while loop.
if (
$original_shift->night_shift==true &&
$p_lookback_night_7===[1,1,1,1,1,1,1] || $p_lookforward_night_7===[1,1,1,1,1,1,1] ||
($p_lookback_night_1===[1] && $p_lookforward_night_6===[1,1,1,1,1,1]) ||
($p_lookback_night_2===[1,1] && $p_lookforward_night_5===[1,1,1,1,1]) ||
($p_lookback_night_3===[1,1,1] && $p_lookforward_night_4===[1,1,1,1]) ||
($p_lookback_night_4===[1,1,1,1] && $p_lookforward_night_3===[1,1,1]) ||
($p_lookback_night_5===[1,1,1,1,1] && $p_lookforward_night_2===[1,1]) ||
($p_lookback_night_6===[1,1,1,1,1,1] && $p_lookforward_night_1===[1])
) {
return 'You can\'t do more than 7 night shifts in a row';
break;
}
The $p_look variables get populated by a loop looking either back of forward the specified number of days at the end of the variable name and returning an array of true or false for that number of days dependent on whether those are night shifts or not.
As an alternative to building several arrays and complex comparisons, this alternative just uses 2 arrays, one with the days prior and one looking forward. I'm not 100% sure if this includes the day they are trying to book off, but hopefully the idea is easy enough to adjust to your needs.
The basic concept is to look backwards through the $p_lookback_night list and count the 1's, stopping when it reaches a 0. It then does a similar thing through the $p_lookforward_night list. The end result is the number of 1's in a row...
$p_lookback_night = [0,0,0,0,1,1];
$p_lookforward_night = [1,1,1,1,0,0];
$run = 0;
foreach (array_reverse($p_lookback_night) as $test ) {
if ( $test == 1 ) {
$run++;
}
else {
break;
}
}
foreach ($p_lookforward_night as $test ) {
if ( $test == 1 ) {
$run++;
}
else {
break;
}
}
echo $run;
With the test data it gives 6, so you can use this to decide if they are trying to book 7 in a row.
Assuming all those arrays can only contain 1 in this case you can simply just count the values
&& count($p_lookback_night_7)===7 || ...
Maybe even use the int at the end dynamically but this will be probably more trouble that it is worth. Something like
for($i=1;$i<8;$i++){
if(count(${"p_lookback_night_".$i}) == $i && count(${"p_lookforward_night_".$i}) == $i ){
..wahtever
}
}

PHP test for empty and/or null and/or unset array

I want to keep this short. I don't know if I have the terminology correct, but I got this example from the Codeigniter handbook Vol.1.
if (count($args) > 1 || is_array($args[0]))
I've run into this problem numerous times. Depending on the datatype different tests are more appropriate. Some tests will just fail in unexpected ways.
How does one determine the most appropriate, and possibly, the most concise test?
Just to be clear I'm looking for the most effective way to test if an object/variable is ready to use, regardless of the datatype, if that's possible.
Also I don't want the solution to apply merely to lists like in the example. It should be widely applicable.
Just use empty
if(!empty($args)){
echo 'Array is set, not empty and not null';
}
use empty() bool empty ( mixed $var )
http://www.php.net/manual/en/function.empty.php
Determine whether a variable is considered to be empty. A variable is considered empty if it does not exist or if its value equals FALSE. empty() does not generate a warning if the variable does not exist.
I've been using the following function for a while.
You can add your own test for all possible variable types.
function is_valid_var($var)
{
if ( isset( $var ) ) {
// string
if ( is_string( $var ) && strlen( $var ) == 0 ) return false;
// array
elseif ( is_array( $var ) && count( $var ) == 0 ) return false;
// unknown
else return true;
}
return false;
}

Categories