Friday 27 March 2015

PHP: What's different with SplFixedArray, and is it best to use?

SplFixedArray is as the name says a fixed size array: You specify the size in the constructor and can only change it later using ->setSize(). But it is not changed automatically. Also you can only use integers as indexes (=> no assoc arrays).

So you can't always use an SplFixedArray when you're using a PHP array (and also shouldn't). But if you are having really large arrays that do not change, then using it can save you some memory.

PHP: array_merge_recursive() vs. array_replace_recursive()

If you’ve been coding in PHP for a while, you have probably used array_merge() at some point. It’s been around since PHP 4, and like most PHP functions, it does largely what you’d expect it to do. If you have arrays with numeric indices, it re-indexes and appends subsequent arrays to the first array argument.
print_r(array_merge(
    array('a', 'b'),
    array('c', 'd')
));
/* the above will output:
Array
(
    [0] => a
    [1] => b
    [2] => c
    [3] => d
)
*/
If you have associative arrays, it doesn’t make much sense to re-index them. Instead, non-numeric keys are … well, merged. Keys from subsequent arrays will overwrite keys with the same name in earlier arrays.
/* note that the key 'B' appears in both arrays */
print_r(array_merge(
    array('A' => 1, 'B' => 2),
    array('B' => 20, 'C' => 30)
));
/* the above will output:
Array
(
    [A] => 1
    [B] => 20
    [C] => 30
)
*/
This is all pretty intuitive. But it gets trickier when you have nested associative arrays to merge. For example, you may have decoded the results from two JSON service calls into arrays, and they both have a top-level data key. array_merge() is not as useful in this case:
print_r(array_merge(
    array(
        'data' => array(
            'collision' => 'first',
            'unique1' => 1,
        )
    ),
    array(
        'data' => array(
            'collision' => 'second',
            'unique2' => 2,
        )
    )
));
/* the above will output:
Array
(
    [data] => Array
        (
            [collision] => second
            [unique2] => 2
        )
)
*/
The first array got clobbered — not quite what you expected, right? Fortunately, there’s a function that will do what you probably want: array_merge_recursive().
print_r(array_merge_recursive(
    array(
        'data' => array(
            'collision' => 'first',
            'unique1' => 1,
        )
    ),
    array(
        'data' => array(
            'collision' => 'second',
            'unique2' => 2,
        )
    )
));
/* the above will output:
Array
(
    [data] => Array
        (
            [collision] => Array
                (
                    [0] => first
                    [1] => second
                )
            [unique1] => 1
            [unique2] => 2
        )
)
*/
In some cases, this behavior isn’t actually what you want. One example is parsing hierarchical config files. If you had a default config and you wanted to merge in a user-specific config, you probably don’t want keys to be merged the way array_merge_recursive() does it. Instead, you would want the user-specific config to replace the default config’s value for that particular key. If you’re running PHP before version 5.3, you’d have to write a custom function to do this. But as of PHP 5.3, there is a new function that does exactly what you want: array_replace_recursive().
print_r(array_replace_recursive(
    array(
        'data' => array(
            'collision' => 'first',
            'unique1' => 1,
        )
    ),
    array(
        'data' => array(
            'collision' => 'second',
            'unique2' => 2,
        )
    )
));
/* the above will output:
Array
(
    [data] => Array
        (
            [collision] => second
            [unique1] => 1
            [unique2] => 2
        )
)
*/
If you’ve written a custom version of array_replace_recursive() and would like to switch to the built-in version, one helpful commenter suggests replacing your custom version with a wrapper that just calls array_replace_recursive(). There are also a few pure-PHP implementations of array_replace_recursive() if you’re stuck with an older version of PHP.

Thursday 19 March 2015

Convert Numbers to Words with PHP

<?php
function convert_number_to_words($number) {
   
    $hyphen      = '-';
    $conjunction = ' and ';
    $separator   = ', ';
    $negative    = 'negative ';
    $decimal     = ' point ';
    $dictionary  = array(
        0                   => 'zero',
        1                   => 'one',
        2                   => 'two',
        3                   => 'three',
        4                   => 'four',
        5                   => 'five',
        6                   => 'six',
        7                   => 'seven',
        8                   => 'eight',
        9                   => 'nine',
        10                  => 'ten',
        11                  => 'eleven',
        12                  => 'twelve',
        13                  => 'thirteen',
        14                  => 'fourteen',
        15                  => 'fifteen',
        16                  => 'sixteen',
        17                  => 'seventeen',
        18                  => 'eighteen',
        19                  => 'nineteen',
        20                  => 'twenty',
        30                  => 'thirty',
        40                  => 'fourty',
        50                  => 'fifty',
        60                  => 'sixty',
        70                  => 'seventy',
        80                  => 'eighty',
        90                  => 'ninety',
        100                 => 'hundred',
        1000                => 'thousand',
        1000000             => 'million',
        1000000000          => 'billion',
        1000000000000       => 'trillion',
        1000000000000000    => 'quadrillion',
        1000000000000000000 => 'quintillion'
    );
   
    if (!is_numeric($number)) {
        return false;
    }
   
    if (($number >= 0 && (int) $number < 0) || (int) $number < 0 - PHP_INT_MAX) {
        // overflow
        trigger_error(
            'convert_number_to_words only accepts numbers between -' . PHP_INT_MAX . ' and ' . PHP_INT_MAX,
            E_USER_WARNING
        );
        return false;
    }

    if ($number < 0) {
        return $negative . convert_number_to_words(abs($number));
    }
   
    $string = $fraction = null;
   
    if (strpos($number, '.') !== false) {
        list($number, $fraction) = explode('.', $number);
    }
   
    switch (true) {
        case $number < 21:
            $string = $dictionary[$number];
            break;
        case $number < 100:
            $tens   = ((int) ($number / 10)) * 10;
            $units  = $number % 10;
            $string = $dictionary[$tens];
            if ($units) {
                $string .= $hyphen . $dictionary[$units];
            }
            break;
        case $number < 1000:
            $hundreds  = $number / 100;
            $remainder = $number % 100;
            $string = $dictionary[$hundreds] . ' ' . $dictionary[100];
            if ($remainder) {
                $string .= $conjunction . convert_number_to_words($remainder);
            }
            break;
        default:
            $baseUnit = pow(1000, floor(log($number, 1000)));
            $numBaseUnits = (int) ($number / $baseUnit);
            $remainder = $number % $baseUnit;
            $string = convert_number_to_words($numBaseUnits) . ' ' . $dictionary[$baseUnit];
            if ($remainder) {
                $string .= $remainder < 100 ? $conjunction : $separator;
                $string .= convert_number_to_words($remainder);
            }
            break;
    }
   
    if (null !== $fraction && is_numeric($fraction)) {
        $string .= $decimal;
        $words = array();
        foreach (str_split((string) $fraction) as $number) {
            $words[] = $dictionary[$number];
        }
        $string .= implode(' ', $words);
    }
   
    return $string;
}
for($i=0;$i < 95;$i++){
echo convert_number_to_words($i);
echo "<br /><br />";
}
?>