Category: tips and tricks

When to use []

This is a shortcut for array_push. It’s easier and even better if you add one element to the array.

Note: If you use array_push() to add one element to the array it's better to use $array[] = because in that way there is no overhead of calling a function.

If you make a mistake and you try to use this on something else than an array, you will have a warning both case. In the doc, you have something else

Note: array_push() will raise a warning if the first argument is not an array. This differs from the $var[] behaviour where a new array is created.
$arr = 5;
array_push($arr, 4);

// PHP Warning:  array_push() expects parameter 1 to be array, integer given

$arr = 5;
$arr[] = 4;

// PHP Warning:  Cannot use a scalar value as an array

// PHP (cli) (built: Mar 24 2015 11:21:10) 
// Copyright (c) 1997-2015 The PHP Group
// Zend Engine v2.6.0, Copyright (c) 1998-2015 Zend Technologies
//     with Zend OPcache v7.0.4-dev, Copyright (c) 1999-2015, by Zend Technologies
//     with Xdebug v2.3.1, Copyright (c) 2002-2015, by Derick Rethans

When not to use []

This is a list of when not to use [] and will result in this error

$a = array();
$b = $a[];
$a = array();
function test($var) { }
$a = array();	
foreach($a[] as $b) {
$a = array();	
foreach($a[]['test'] as $b) {
$a = array();
foreach($a['test'][] as $b) {

You can find more example here

The problem i had

I came accros some code trying to use variables variables and []. Since the precedence is kind of blurry here, i got this error in this particular scenario.

$test = 'var';
$name = 'test' . $test;

$testvar = array();
$$name[] = 3; // Add something to $testvar

// PHP Fatal error:  Cannot use [] for reading

The solution

1- Use array_push : array_push($$name, 3);
2- Use {} to force precedence : ${$name}[] = 3;

What i have found

I ran it over 3v4l and it seems to work now on php7@20140901 – 20150501



class test   {  
        private $data = array();        
        public function __get($name) {
            return isset($this------->data[$name]) ? $this->data[$name] : null;

        public function __set($name, $value) {
            $this->data[$name] = $value;

        public function run() {
            $this->test = array('first' => 1);
            $this->test['second'] = 2;

$test = new test();

 // OUTPUT :
 // PHP Notice:  Indirect modification of overloaded property test::$test has no effect in /data/test/test22.php on line 13

The problem

You see “test” is not a property of this class. So it’s calling the Magic Method __get() but since it’s return by value, the modification on line 26 has no effect. You will have this problem for array and object.


  1. Instead of adding a new item directly, you could use array_merge or use the + operator
  2. You could return __get by reference
  3. You could specify the property directly in the class
   // solution #1
   $this->test += array('second' => 2);
   $this->test = array_merge($this->test, array('second' => 2);

   // solution #2
   public function &__get($name) { ... }

   // solution #2
   private $test = array(); // With the data property

List of related links

CAUTION : PHP reserves all function names starting with __ as magical. It is recommended that you do not use function names with __ in PHP unless you want some documented magic functionality.


I have no idea, but someone ask about it


  • Backup, backup again and again just to be sure
  •  In your 2.4 redis.conf, set the following properties to zero ; hash-max-zipmap-entries, list-max-ziplist-entries, set-max-intset-entries
  • Restart redis and do SAVE command OR BGSAVE
  • Edit dump.rdb file. Change first character to REDIS0001
  • Copy to 2.0 instance and restart redis.

Why ENV is empty

The problem :

I want to use $_ENV so i can get the username of the logged user.  Everyone should use getenv() instead, but if you need $_ENV to be active you need to do this.

Edit your php.ini file. You can find which one you are using with "php -i" from cli or with phpinfo() through your browser. Search for "variable_orders"and set it to
variables_order = "GPCSE"

Each letter is for one superglobals variable ( get, post, cookie, server and env ). You need to know that each one you add will cause some performance penalty and this is why normally you don't add the letter "e".

From the php.ini file:

; This directive determines which super global arrays are registered when PHP
; starts up. If the register_globals directive is enabled, it also determines
; what order variables are populated into the global space. G,P,C,E & S are
; abbreviations for the following respective super globals: GET, POST, COOKIE,
; ENV and SERVER. There is a performance penalty paid for the registration of
; these arrays and because ENV is not as commonly used as the others, ENV is
; is not recommended on productions servers. You can still get access to
; the environment variables through getenv() should you need to.
; Default Value: "EGPCS"
; Development Value: "GPCS"
; Production Value: "GPCS";

From the doc:

Sets the order of the EGPCS (Environment, Get, Post, Cookie, and Server) variable parsing. For example, if variables_order is set to "SP" then PHP will create the superglobals $_SERVER and $_POST, but not create $_ENV, $_GET, and $_COOKIE. Setting to "" means no superglobals will be set.

If the deprecated register_globals directive is on, then variables_order also configures the order the ENV, GET, POST, COOKIE and SERVER variables are populated in global scope. So for example if variables_order is set to "EGPCS", register_globals is enabled, and both $_GET['action'] and $_POST['action'] are set, then $action will contain the value of $_POST['action'] as P comes after G

You know what is array_rand and you use it sometimes like rand() ( maybe mt_rand() if you want better random value). Anyway, i was reading this page when i saw the comment by Sebmil. This was pretty weird and i tried to figure it out why. This is in progress, because i did not found the reason.  I'm using php 5.3.6-p10-gentoo but i tested on ubuntu with 5.3.2 and i'm pretty sure it's all around.
$values = range(0, 49);
$prob = array_fill(0, 50, 0);
for ($i = 0; $i < 10000; $i++) {     $rand = array_rand($values, 10);     foreach($rand as $key => $value) {

/** Output something like this:
*  "30" will always be at the top
  <strong>30 => int 1842</strong>
  40 => int 1934
  3 => int 1935
  10 => int 1940
  45 => int 1942
  28 => int 1949
  14 => int 1962
  47 => int 1965
  22 => int 1965
  19 => int 1968

What do i know ?!?

  • If the second params of for is lower ( like 50 ) , the output seem random.
  • If we use rand() in each loop the "lower" value (30) will change. One for each rand() used. When we reach 3 ( about 27 rand() calls ),  the output seem random.
  • If we use rand() or mt_rand() instead of array_rand, the output seem random.
  • php 5.4 trunk array_rand function doesn't seem to have changed.

array_rand() source php 5.3 trunk :

Can you figure out where the bug is ?
/* {{{ proto mixed array_rand(array input [, int num_req])
   Return key/keys for random entry/entries in the array */
        zval *input;
        long randval, num_req = 1;
        int num_avail, key_type;
        char *string_key;
        uint string_key_len;
        ulong num_key;
        HashPosition pos;

        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|l", &input, &num_req) == FAILURE) {

        num_avail = zend_hash_num_elements(Z_ARRVAL_P(input));

        if (ZEND_NUM_ARGS() > 1) {
                if (num_req  num_avail) {
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "Second argument has to be between 1 and the number of elements in the array");

        /* Make the return value an array only if we need to pass back more than one result. */
        if (num_req > 1) {
                array_init_size(return_value, num_req);

        /* We can't use zend_hash_index_find() because the array may have string keys or gaps. */
        zend_hash_internal_pointer_reset_ex(Z_ARRVAL_P(input), &pos);
        while (num_req && (key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(input), &string_key, &string_key_len, &num_key, 0, &pos)) != HASH_KEY_NON_EXISTANT) {

                randval = php_rand(TSRMLS_C);

                if ((double) (randval / (PHP_RAND_MAX + 1.0)) < (double) num_req / (double) num_avail) {
                        /* If we are returning a single result, just do it. */
                        if (Z_TYPE_P(return_value) != IS_ARRAY) {
                                if (key_type == HASH_KEY_IS_STRING) {
                                        RETURN_STRINGL(string_key, string_key_len - 1, 1);
                                } else {
                        } else {
                                /* Append the result to the return value. */
                                if (key_type == HASH_KEY_IS_STRING) {
                                        add_next_index_stringl(return_value, string_key, string_key_len - 1, 1);
                                } else {
                                        add_next_index_long(return_value, num_key);
                zend_hash_move_forward_ex(Z_ARRVAL_P(input), &pos);

Possible solution :

  1. Shuffle() your array in each loop
  2. Use multiple time rand()
  3. Don't use array_rand too often.

Tips and Tricks #1

FOREACH reference:

$myArray = array('t','h','i','s','i','s','a','n','a','r','r','a','y');
foreach($myArray as &$value) {
  echo $value;
echo PHP_EOL;
foreach($myArray as $v) {
  echo $v;
echo PHP_EOL;
foreach($myArray as $value) {
  echo $value;

The reason is almost obvious when you know you’re using reference and you know how reference works. When you are using reference , $value is a pointer to your element , not a copied value. So when you loop over your array, $value will be each element from your array. Everything is ok until you use the variable again. Everything you will assign to it , will also change the value of the reference. Another example to explain :

$myArray = array('t','h','i','s');  
 foreach($myArray as &$value) {
           echo $value;
  echo PHP_EOL;
  $value = 'reference value changed';
/*  OUTPUT:  
array(4) {
  string(1) "t"
  string(1) "h"
  string(1) "i"
  &string(23) "reference value changed"

You only need to unset the reference. In this case : $value. If you want a more detail explication , check out Johannes Schlüter blog