Can this be done in 1 line? - php

Can this be done in 1 line with PHP?
Would be awesome if it could:
$out = array("foo","bar");
echo $out[0];
Something such as:
echo array("foo","bar")[0];
Unfortunately that's not possible. Would it be possible like this?
So I can do this for example in 1 line:
echo array(rand(1,100), rand(1000,2000))[rand(0,1)];
So let's say I have this code:
switch($r){
case 1: $ext = "com"; break;
case 2: $ext = "nl"; break;
case 3: $ext = "co.uk"; break;
case 4: $ext = "de"; break;
case 5: $ext = "fr"; break;
}
That would be much more simplified to do it like this:
$ext = array("com","nl","co.uk","de","fr")[rand(1,5)];

Why not check out the array functions on the PHP site?
Well, if you're picking a random element from the array, you can use array_rand().
$ext = array_rand(array_flip(array("com","nl","co.uk","de","fr")));

echo array_rand(array_flip(array('foo', 'bar')));
array flip takes an array and swaps the keys with the values and vice versa. array_rand pulls a random element from that array.

You can use a shorthand form to keep things on one line and avoid creating an array that will never be used again.
echo rand(0,1) ? rand(1,100) : rand(1000,2000);

Yes, list a PHP language construct that allows the syntax below.
list( $first_list_element ) = array( "foo", ..... );
EDIT:
Still Yes, Missed the echo. Reset will return the first array item, which might not always be index 0, but if you create an array normally it will.
echo reset( array( "foo",... ) );
EDIT AGAIN:
After you updated your question I see that you want something that PHP just can't do well. I personally think it's a syntax design error of the PHP language/interpreter. If you just mean one-line you could do.
$array = array( .... ); echo $array[0];

I think your example may not be the best. The real syntax limitation here is that one can not immediately perform array access on the returned value of a function call, as in,
do_something_with(explode(',', $str)[0]);
And you pretty much can't get around it. Assign to a variable, then access. It's a silly limitation of PHP, but it's there.
You can technically do,
function array_access($array, $i) {
return $array[$i];
}
do_something_with(array_access(explode(',', $str), 0));
But please don't. It's even uglier than an extra variable asignment.
(Given the edit to the question, this no longer a sufficient answer. However, I will leave it up for reference.)

Like #Matchu's answer, this addresses the more general case, ie you have an array value that came from somewhere, be it a function call, an instantiated array, whatever. Since the return value from an arbitrary function is the least specific case, I'll use a call to some_function() in this example.
$first_element = current(array_slice(some_function(), 0, 1));
So you could randomize it with
$random_element = current(array_slice(some_function(), rand(0,1), 1));
but in that case (as in many in php) there is a more specialized function for that; see #animuson's answer.
edited
changed array_shift() call to current() call: this is more efficient, because array_shift() will modify the intermediate array returned by array_slice().

This is being discussed in the internals mailing list right now. You might want to check it: http://marc.info/?l=php-internals&m=127595613412885&w=2

print $a[ array_rand($a = array('com','nl','co.uk','de','fr')) ];

Related

php using array_flip to check if value exists vs iterating and if statement

I have a series of arrays and usually if i want to check if a value exists i iterate throu the array, use an if statement inside the foreach block then break or return, but recently I decided to use array_flip to flip the array then check if the key exists with isset:
<?php
$arr = array(1, 0, 'yes', 'no', 'on', 'off' /* more keys */);
/*
foreach($arr as $value) {
if ($value === 'on') { return 'xxx'; }
}
*/
//Alternative
$arrFlipped = array_flip($arr);
if (isset($arrFlipped['on'])) { return xxx; }
?>
The arrays are made from safe data, not user input, so the values would always be valid keys.
I'd like to know if this appoach is ok, what are the advantages and disadvantages?, wich one is faster or waste less resources?
Sorry for my english... thanks!
Edit:
OP asks for multiple values
Don't.
First, it might look like an optimisation in your code, but the performance will not change: in the background, PHP will have to loop through the array anyway.
Second, don't be "smart". The more "tricks" you use in your code, the harder it is to maintain your code. 6 months from now, you'll be scratching your head wondering why the ** you decided to flip the array (you or whoever is tasked to maintain your code).
If you really want to implement something like that, at least encapsulate in a clearly named function so that you can see what you were going for:
function value_exists($arr, $value){
$arrFlipped = array_flip($arr);
if (isset($arrFlipped["$value"])) { return xxx;
}else{ return false; }
}
That way, when you write return value_exists($arr, $value); what you're doing is obvious, even if your implementation is unusual.
Third, you can use in_array or array_search to do what you want.
Fourth, if you are looking for optimizations and you aren't sure if it makes it better, just profile it. The easiest way is to use microtime:
$before = microtime(true);
// code to test
$now = microtime(true);
echo sprintf("Elapsed: %f", $now-$before);
But you shouldn't be trying to optimize for performance unless you notice an actual problem.
What about in_array?
return in_array('on', array(1, 0, 'yes', 'no', 'on', 'off'))
http://php.net/manual/en/function.in-array.php
To check if multiple values exists in array , like you said in comment , use :
array_intersect() returns an array containing all the values of array1 that are present in all the arguments. Note that keys are preserved.
Intersect the $target with the $arr and make sure the intersection is precisely equal to the number of elements in $target:
$arr = array(1, 0, 'yes', 'no', 'on', 'off' /* more keys */);
$target = array('yes', 'off');
if(count(array_intersect($arr, $target)) == count($target)){
echo 'all values found in array' ;
}
This works also for one element , but it should be in array as well

How do I use multiple list()/each() calls in a while loop?

I'm working with 3 different arrays (although I'm only testing with two for the time being) and I'm trying to process the arrays on $_POST. I'm currently using:
while(list($key_member,$member)=each($_POST['member_ids'])
&& list($key_amount,$amount)=each($_POST['payment_amounts']))
{
echo "MEMBER: $member<br>";
echo "AMOUNT: $amount<br><br>";
}
If I use one list() on either array it will print the info for that particular item. However, if I attempt to use multiple list() commands in the while, only the last list()ed item gets filled properly. Is list() doing some trickery in the background that's preventing it from working in a while loop?
Obviously the "easy" solution would be to use an index and simply force the issue, but I prefer enumerating -- and I'm honestly just curious as to
What am I doing wrong, and/or what is "broken" with list()?
bug? dunno.
here's a workaround.
while(list($key_member,$member)=each($_POST['member_ids'])){
list($key_amount,$amount)=each($_POST['payment_amounts']);
echo "MEMBER: $member<br>";
echo "AMOUNT: $amount<br><br>";
}
You could extract each array's keys using array_keys(), which produces an indexed array, then keep separate loop counters for each array:
$member_ids = array_keys($_POST['member_ids']);
$amounts = array_keys($_POST['payment_amounts']);
$mi = 0;
$am = 0;
while(1) {
...
$mi++
$am++;
if (count($member_ids) >= $mi) && (count(amounts) >= $am) {
break;
}
}
&& is evaluated in a short-circuit manner, the first statement to return false jumps out of it. In your case it stops to iterate as soon as the first array is at its end. list should work fine here, as it's a language construct which assigns variables.

Why doesn't my code to test an email address against a specific domain work?

I wanted to allow only specific email domain. Actually I did it. What i wanted to ask why my first code did not work at all.
I am just trying to learn PHP so that the question may seem silly, sorry for that.
Here is my code:
function check_email_address($email) {
$checkmail = print_r (explode("#",$email));
$container = $checkmail[1];
if(strcmp($container, "gmail.com")) {
return true;
}else {
return false;
}
}
Check out the documentation for strcmp() , it will return 0 of the two strings are the same, so that's the check you want to be doing. Also, you're using print_r() when you shouldn't be, as mentioned by the other answerers.
Anyway, here's how I would have done the function - it's much simpler and uses only one line of code:
function check_email_address($email) {
return (strtolower(strstr($email, '#')) == 'gmail.com');
}
It uses the strstr() function and the strtolower() function to get the domain name and change it to lower case, and then it checks if it is gmail.com or not. It then returns the result of that comparison.
It's because you're using print_r. It doesn't do what you seem to expect from it at all. Remove it:
$checkmail = explode("#", $email);
You can find the docs about print_r here:
http://php.net/print_r
Besides that, you can just use the following (it's much shorter):
$parts = explode("#", $email);
return (strcmp($parts[1], "gmail.com") == 0);
The following row doesn't work as you think it does:
$checkmail = print_r (explode("#",$email));
This means that you're trying to assign the return value from print_r() into $checkmail, but it doesn't actually return anything (if you don't supply the second, optional parameter with the value true).
Even then, it would've gotten a string containing the array structure, and your $container would have taken the value r, as it's the second letter in Array.
Bottom line: if your row would've been without the call to print_r(), it would've been working as planned (as long as you made sure to compare the strcmp() versus 0, as it means that the strings are identical).
Edit:
Interesting enough, I just realized that this could be achieved with the use of substr() too:
<?php
//Did we find #gmail.com at the end?
if( strtolower(substr($email, -10)) == '#gmail.com' ) {
//Do something since it's an gmail.com-address
} else {
//Error handling here
}
?>
You want:
if(strcmp($container, "gmail.com")==0)
instead of
if(strcmp($container, "gmail.com"))
Oh! And no inlined print_r() of course.
Even better:
return strcmp($container, "gmail.com")==0;
No need for the print_r; explode returns a list. And in terms of style (at least, my style) no need to assign the Nth element of that list to another variable unless you intend to use it a lot elsewhere. Thus,
$c = explode('#',$mail);
if(strcmp($c[1],'gmail.com') == 0) return true;
return false;

PHP: testing for existence of a cell in a multidimensional array

I have an array with numerous dimensions, and I want to test for the existence of a cell.
The below cascaded approach, will be for sure a safe way to do it:
if (array_key_exists($arr, 'dim1Key'))
if (array_key_exists($arr['dim1Key'], 'dim2Key'))
if (array_key_exists($arr['dim1Key']['dim2Key'], 'dim3Key'))
echo "cell exists";
But is there a simpler way?
I'll go into more details about this:
Can I perform this check in one single statement?
Do I have to use array_key_exist or can I use something like isset? When do I use each and why?
isset() is the cannonical method of testing, even for multidimensional arrays. Unless you need to know exactly which dimension is missing, then something like
isset($arr[1][2][3])
is perfectly acceptable, even if the [1] and [2] elements aren't there (3 can't exist unless 1 and 2 are there).
However, if you have
$arr['a'] = null;
then
isset($arr['a']); // false
array_key_exists('a', $arr); // true
comment followup:
Maybe this analogy will help. Think of a PHP variable (an actual variable, an array element, etc...) as a cardboard box:
isset() looks inside the box and figures out if the box's contents can be typecast to something that's "not null". It doesn't care if the box exists or not - it only cares about the box's contents. If the box doesn't exist, then it obviously can't contain anything.
array_key_exists() checks if the box itself exists or not. The contents of the box are irrelevant, it's checking for traces of cardboard.
I was having the same problem, except i needed it for some Drupal stuff. I also needed to check if objects contained items as well as arrays. Here's the code I made, its a recursive search that looks to see if objects contain the value as well as arrays. Thought someone might find it useful.
function recursiveIsset($variable, $checkArray, $i=0) {
$new_var = null;
if(is_array($variable) && array_key_exists($checkArray[$i], $variable))
$new_var = $variable[$checkArray[$i]];
else if(is_object($variable) && array_key_exists($checkArray[$i], $variable))
$new_var = $variable->$checkArray[$i];
if(!isset($new_var))
return false;
else if(count($checkArray) > $i + 1)
return recursiveIsset($new_var, $checkArray, $i+1);
else
return $new_var;
}
Use: For instance
recursiveIsset($variables, array('content', 'body', '#object', 'body', 'und'))
In my case in drupal this ment for me that the following variable existed
$variables['content']['body']['#object']->body['und']
due note that just because '#object' is called object does not mean that it is. My recursive search also would return true if this location existed
$variables->content->body['#object']->body['und']
For a fast one liner you can use has method from this array library:
Arr::has('dim1Key.dim2Key.dim3Key')
Big benefit is that you can use dot notation to specify array keys which makes things simpler and more elegant.
Also, this method will work as expected for null value because it internally uses array_key_exists.
If you want to check $arr['dim1Key']['dim2Key']['dim3Key'], to be safe you need to check if all arrays exist before dim3Key. Then you can use array_key_exists.
So yes, there is a simpler way using one single if statement like the following:
if (isset($arr['dim1Key']['dim2Key']) &&
array_key_exists('dim3Key', $arr['dim1Key']['dim2Key'])) ...
I prefer creating a helper function like the following:
function my_isset_multi( $arr,$keys ){
foreach( $keys as $key ){
if( !isset( $arr[$key] ) ){
return false;
}
$arr = $arr[$key];
}
return $arr;
}
Then in my code, I first check the array using the function above, and if it doesn't return false, it will return the array itself.
Imagine you have this kind of array:
$arr = array( 'sample-1' => 'value-1','sample-2' => 'value-2','sample-3' => 'value-3' );
You can write something like this:
$arr = my_isset_multi( $arr,array( 'sample-1','sample-2','sample-3' ) );
if( $arr ){
//You can use the variable $arr without problems
}
The function my_isset_multi will check for every level of the array, and if a key is not set, it will return false.

PHP: Can I reference a single member of an array that is returned by a function?

any idea how if the following is possible in PHP as a single line ?:
<?php
$firstElement = functionThatReturnsAnArray()[0];
... It doesn't seem to 'take'. I need to do this as a 2-stepper:
<?php
$allElements = functionThatReturnsAnArray();
$firstElement = $allElements[0];
... just curious - other languages I play with allow things like this, and I'm lazy enoug to miss this in PHP ... any insight appreciated ...
#Scott Reynen
that's not true. This will work:
list(,,$thirdElement) = $myArray;
Try:
<?php
$firstElement = reset(functionThatReturnsAnArray());
If you're just looking for the first element of the array.
Unfortunately, that is not possible with PHP. You have to use two lines to do it.
You can do this in one line! Use array_shift().
<?php
echo array_shift(i_return_an_array());
function i_return_an_array() {
return array('foo', 'bar', 'baz');
}
When this is executed, it will echo "foo".
list() is useful here. With any but the first array element, you'll need to pad it with useless variables. For example:
list( $firstElement ) = functionThatReturnsAnArray();
list( $firstElement , $secondElement ) = functionThatReturnsAnArray();
And so on.
I actually use a convenience function i wrote for such purposes:
/**
* Grabs an element from an array using a key much like array_pop
*/
function array_key_value($array, $key) {
if(!empty($array) && array_key_exists($key, $array)) {
return $array[$key];
}
else {
return FALSE;
}
}
then you just call it like so:
$result = array_key_value(getMeAnArray(), 'arrayKey');
You can use array_slice(), like so:
$elementX = array_slice(functionThatReturnsAnArray(), $x, 1);
Also noticed that end() is not mentioned. It returns the last element of an array.
Either current($array) or array_shift($array) will work, the former will leave the array intact.
nickf, good to know, thanks. Unfortunately that has readability problems beyond a few commas.
I think any of the above would require a comment to explain what you're doing, thus becoming two lines. I find it simpler to do:
$element = functionThatReturnsArray();
$element = $element[0];
This way, you're not using an extra variable and it's obvious what you're doing.
$firstItem = current(returnsArray());
Well, I have found a couple of ways to get what you want without calling another function.
$firstElement = ($t = functionThatReturnsAnArray()) ? $t[0] : false;
and for strings you could use
$string = (($t = functionThatReturnsAnArray())==0) . $t[0];
.. Interesting problem
Draco
I am guessing that this is a built-in or library function, since it sounds like you cannot edit it directly. I recommend creating a wrapper function to give you the output you need:
function functionThatReturnsOneElement( $arg )
{
$result = functionThatReturnsAnArray( $arg );
return $result[0];
}
$firstElement = functionThatReturnsOneElement();
As far as I know this is not possible, I have wanted to do this myself several times.
http://us3.php.net/reset
Only available in php version 5.
If it's always the first element, you should probably think about having the function return just the first item in the array. If that is the most common case, you could use a little bit of coolness:
function func($first = false) {
...
if $first return $array[0];
else return $array;
}
$array = func();
$item = func(true);
My php is slightly rusty, but i'm pretty sure that works.
You can also look at array_shift() and array_pop().
This is probably also possible:
array(func())[0][i];
The 0 is for the function.
Sometimes I'll change the function, so it can optionally return an element instead of the entire array:
<?php
function functionThatReturnsAnArray($n = NULL) {
return ($n === NULL ? $myArray : $myArray[$n]);
}
$firstElement = functionThatReturnsAnArray(0);

Categories