<?php
/*
A non-exhaustive look at array capabilities of PHP.
Made for educational purpose, and to allow comparison of syntax/features
of Lua and JavaScript in the same domain.

by Philippe Lhoste <PhiLho(a)GMX.net> http://Phi.Lho.free.fr
File/Project history:
 1.00 -- 2007/04/17 (PL) -- Creation.

Copyright notice: See the PhiLhoSoftLicence.txt file for details.
This file is distributed under the zlib/libpng license.
Copyright (c) 2007 Philippe Lhoste / PhiLhoSoft
*/
?>
<!DOCTYPE html PUBLIC
      "-//W3C//DTD XHTML 1.0 Transitional//EN"
      "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <title>Testing PHP array operations</title>

  <!-- For dynamically generated pages -->
  <meta http-equiv="pragma" content="no-cache" />
  <meta http-equiv="cache-control" content="no-cache" />
  <meta http-equiv="expires" content="0" />

  <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
  <meta http-equiv="Content-Language" content="en-EN" />

  <meta name="Author" content="Philippe Lhoste" />
  <meta name="Copyright" content="Copyright (c) 2006 Philippe Lhoste" />
  <meta name="Generator" content="My typing hands with SciTE" />
  <meta http-equiv="Keywords" content="test,php,language" />
  <meta http-equiv="Description" content="A test page for PHP experiments" />

<style type="text/css">
body { background-color: #F0F8F0; }
h1
{
  background-color: #BFC;
  color: #008;
  text-align: center;
  padding: 20px;
}
h2
{
  background-color: #DFE;
  color: #088;
  padding: 10px;
}
h3
{
  background-color: #DFE;
  color: #088;
  padding: 5px;
}
pre
{
  background-color: #FAFAFF;
  color: #228;
}
</style>
</head>

<body>
<?php
if (isset($_GET['source']))
{
    
highlight_file('TestPHPArray.php');
    exit();
}
?>

<h1>Testing PHP array operations</h1>

<h2>Simple array</h2>

<?php

// http://www.php.net/manual/en/ref.array.php

///// Arrays with numerical index

// Simple definition and putting values in it
$simpleArray = array();
$simpleArray[0] = "GET";
$simpleArray[1] = "POST";
$simpleArray[2] = "PUT";
$simpleArray[3] = "DELETE";

// Pre-definition (no pre-def size, no initialization with an array literal), automatic index increase
$predefinedArray = array();
$predefinedArray[] = "HTTP";
$predefinedArray[] = "FTP";
$predefinedArray[] = "NNTP";
$predefinedArray[] = "IRC";
// We can skip entries
// Slots 4 and 5 are empty
$predefinedArray[count($predefinedArray) + 2] = "FTPS";

// Definition and initialization at once
$initializedArray = array("html""head""body", );    // Trailing comma is OK

// Generating an array
$generatedArray1 explode(":""a:b:i:p:u:random:garbage"5);
$generatedArray2 preg_split("/\s*[;,]\s*/""hr , br ;  p , span, div");

// Assigning an array
$gArray explode(" - ""aa - bb - cc - dd - ee");
$aArray $gArray;  // aArray gets a copy, the arrays are independent
$gArray[3] = "gg";
$aArray[4] = "zz";

// Array as function parameter and return value
function ProcessArrayV($a)
{
  
$a[0] = "ff0";  // Change copy of array
  
$la = array("1""2""3"$a); // Get a copy
  
$a[1] = "ff1";  // Change is lost
  
return $la;
}
$fcvArray = array("F1""F2""F3");
$frvArray ProcessArrayV($fcvArray);

function 
ProcessArrayR(&$a)
{
  
$a[0] = "ff0";  // Change array
  
$la = array("1""2""3", &$a); // Get a reference
  
$a[1] = "ff1";  // Change in both arrays
  
return $la;
}
$fcrArray = array("F1""F2""F3");
$frrArray ProcessArrayR($fcrArray);

// Putting arrays in an array
$subArray1 = array("com""org""net""int");
$subArray2 = array("edu""mil""gov");
$multiDimensionalArray = array(
    
22 7,
    
"TLDs",
    
$subArray1,
    
$subArray2,
    
42,
);

$result "";
$result .= FormatArrayMessage("simple"$simpleArray'n'"\n");
$result .= FormatArrayMessage("predefined"$predefinedArray'n'" -- Notice empty slots\n");
$result .= FormatArrayMessage("initialized"$initializedArray);
$result .= FormatArrayMessage("generated 1"$generatedArray1);
$result .= FormatArrayMessage("generated 2"$generatedArray2);
$result .= FormatArrayMessage("original"$gArray);
$result .= FormatArrayMessage("assigned"$aArray);
$result .= FormatArrayMessage("function call by value"$fcvArray);
$result .= FormatArrayMessage("function return"$frvArray'n');
$result .= FormatArrayMessage("function call by ref"$fcrArray);
$result .= FormatArrayMessage("function return"$frrArray'n');
$result .= FormatArrayMessage("multi-dimensional"$multiDimensionalArray'n');

ShowResult($result"Array Init");


// Getting values:
$result "";
$result .= $simpleArray[2] . "\n";
$result .= $predefinedArray[2] . "\n";
$result .= $initializedArray[1] . "\n";
$result .= $multiDimensionalArray[2][1] . "\n";

// @ prevents a warning on undefined offset
$r = @$predefinedArray[1];
$result .= "[1] is: $r - " .
        (isset(
$r) ? "set" "unset") . " / " .
        (empty(
$r) ? "empty" "not empty") . "\n";
$r = @$predefinedArray[100];
$result .= "[100] is: $r - " .
        (isset(
$r) ? "set" "unset") . " / " .
        (empty(
$r) ? "empty" "not empty") . "\n";

ShowResult($result"Array Access");


// Some array operations
$result "";
$predefinedArray[7] = "POP3";
$predefinedArray[42] = "Z1";
$predefinedArray[] = "Z2";
// Array operators
// + overwrites the keys/indexes in the left array with those in the right array
$resultArray $subArray2 $subArray1;

$result .= FormatMessage("array"ToString($predefinedArray'n')) .
    
FormatMessage("size"count($predefinedArray)) .
    
FormatMessage("is_array"ShowBoolean(is_array($predefinedArray))) .
    
FormatMessage("array addition"ToString($resultArray'n')) . "\n";

sort($predefinedArray); // Lot of variants: http://www.php.net/manual/en/function.sort.php
$result .= FormatArrayMessage("sort"$predefinedArray'n'" -- Empty elements removed");

$r array_pop($predefinedArray);   // Remove last element
$result .= FormatArrayMessage("array_pop"$predefinedArray'v'" '" $r "' removed");

$predefinedArray array_reverse($predefinedArray);
$result .= FormatArrayMessage("array_reverse"$predefinedArray'v');

$r array_shift($predefinedArray); // Remove first element
$result .= FormatArrayMessage("array_shift"$predefinedArray'v'" '" $r "' removed");

$predefinedArray[0] = "HTTPS";
$result .= FormatArrayMessage("(replace) 0"$predefinedArray);

$r array_splice($predefinedArray12"messaging");  // Remove 2, insert 1 in place
$result .= FormatArrayMessage("splice 1 2 s"$predefinedArray'v'" '" ToString($r'v') . "' removed");

$r array_splice($predefinedArray31);  // Remove 2, insert 1 in place
$result .= FormatArrayMessage("splice 3 1"$predefinedArray'v'" '" ToString($r'v') . "' removed");

$r array_splice($predefinedArray10, Array("POP3""IMAP4"));  // Insert 2
$result .= FormatArrayMessage("splice 1 0 s s"$predefinedArray'v'" '" ToString($r'v') . "' removed");

$r array_push($predefinedArray"Y""Z");    // Add at end
$result .= FormatArrayMessage("push Y Z"$predefinedArray);

$r array_unshift($predefinedArray"A""B");    // Insert at beginning
$result .= FormatArrayMessage("unshift A B"$predefinedArray);

$r array_slice($predefinedArray24);   // Take a slice of arg2 chars, from position arg1
$result .= FormatArrayMessage("array_slice 2 4"$r);

$r array_slice($predefinedArray6);   // Take a slice from position arg1 up to the end
$result .= FormatArrayMessage("array_slice 6"$r);

$predefinedArray array_slice($predefinedArray2, -2);    // Take a slice from position arg1 up to arg2 elements from the end of the array
$result .= FormatArrayMessage("array_slice 2 -2"$predefinedArray);

$predefinedArray array_merge($predefinedArray$simpleArray$initializedArray);
$result .= FormatArrayMessage("array_merge a1 a2"$predefinedArray);


$result .= PadMessage("in_array") .
        
"HTTP: " ShowBoolean(in_array("HTTP"$predefinedArray)) .
        
", DEL: " ShowBoolean(in_array("DEL"$predefinedArray)) . " (only full match)" .
        
", http: " ShowBoolean(in_array("http"$predefinedArray)) . " (case sensitive)\n";
$result .= PadMessage("array_search") .
        
"HTTP: " array_search("HTTP"$predefinedArray) .
        
", DEL: " array_search("DEL"$predefinedArray) . " (only full match)" .
        
", http: " array_search("http"$predefinedArray) . " (case sensitive)\n";

$result .= PadMessage("implode ' | '") . implode(" | "$predefinedArray) . "\n";

// There are lot of other operations, inconsistently named (with or without array_ prefix)
// and made (sort change array, array_reverse doesn't...),
// lot of them being probably rarely used or can be done by walking the array(s)...
// There are also array operators, but I rule them out...

ShowResult($result"Array Operations");


$result PadMessage("foreach");
foreach (
$predefinedArray as $i => $element)
{
    
$result .= "[$i] $element, ";
}
$result .= "\n";
$result .= PadMessage("for");
for (
$i 0$c count($predefinedArray); $i $c$i++)
{
    if (isset(
$predefinedArray[$i]))
        
$result .= "[$i] {$predefinedArray[$i]}, ";
}
$result .= "\n";

ShowResult($result"Array Iteration");
?>

<h2>Associative array</h2>

<?php
///// Associative arrays

// Manual creation
$aaSimple = array();
$aaSimple["one"] = "1";
$aaSimple["two"] = "2_2";
$aaSimple["three"] = "3_3_3";
$aaSimple["#@!\\%"] = "garbage";

// Object literal
$aaLiteral =
array(
  
"one" => "un_uno_ichi",
  
"two" => "deux_dos_ni",
  
"three" => "trois_tres_san",
  
"and... more" => "...",
);

$aaId =
array(
  
'one' => "1"'un' => 1'uno' => true'ichi' => 1.0
);

// The values can be numerical, string or array
$x 12345;
$aaVal =
array(
  
=> "1",
  
'' => $aaId,
  
'no index item',  // Disappear!?
  
$x => array(42),
  
'in numerical slot',
  
3.14159 => $aArray,
  
.0 => $x,
);
$aaVal[2] = "2";
$aaNested =
array(
  
'deep' =>
  array(
    
'into' =>
    array(
      
'array' => '!'
    
)
  )
);


$result "";
$result .= FormatArrayMessage("simple"$aaSimple'k');
$result .= FormatArrayMessage("literal"$aaLiteral'k');
$result .= FormatArrayMessage("id"$aaId'k');
$result .= FormatArrayMessage("val"$aaVal'n');
$result .= FormatArrayMessage("nested"$aaNested'n');

ShowResult($result"Associative Array Init");


// Getting values:
$result "";
$result .= $aaSimple["two"] . "\n";
$result .= $aaSimple['th' 'ree'] . "\n";
$result .= $aaSimple["#@!\\%"] . "\n";
$result .= @$aaSimple[1] . "\n";  // Doesn't exist
$result .= @$aaSimple['unknown'] . "\n";  // Doesn't exist
$result .= $aaVal[1] . "\n";
$result .= $aaVal['']['uno'] . "\n";
$result .= $aaNested['deep']['into']['array'] . "\n";

ShowResult($result"Associative Array Access");


// Some array operations
$result "";
$aaLiteral['newOne'] = "New entry";
$aaLiteral[1] = 1;
$aaLiteral["+-/*"] = "ops";
$result .= FormatArrayMessage("(add)"$aaLiteral'k');

unset(
$aaLiteral['two']);
unset(
$aaLiteral[1]);
unset(
$aaLiteral['and... more']);
$result .= FormatArrayMessage("(delete) unset"$aaLiteral'k');

$aaC $aaSimple $aaLiteral $aaId $aaNested;
$result .= FormatArrayMessage("merge"$aaC'k');

$r shuffle($aaC);
$result .= FormatArrayMessage("shuffle"$aaC'k');
$r sort($aaC);    // Seems to depend on shuffle result! Very strange...
$result .= FormatArrayMessage("sort"$aaC'k');

//~ $result .= FormatArrayMessage("", $predefinedArray, 'n', "\n");
//~ $result .= FormatArrayMessage("", $predefinedArray);
// Being used to Lua giving no guarantee on the order of associative entries,
// I was surprised to see that PHP memorizes the order of putting values in the ass. array,
// and uses it in operations like array_pop...
// I won't retry the above operations (on plain arrays) here...



ShowResult($result"Associative Array Operations");

?>

<hr />
<a href="TestPHPArray.php?source">View source of this page</a>

</body>
</html>

<?php
// Helper functions

function PadMessage($message)
{
  return 
str_pad($message ':'25);
}
// Data formating with message
function FormatMessage($message$data$after='')
{
  return 
PadMessage($message) . $data $after "\n";
}
// Array formating with message
function FormatArrayMessage($message$array$style='v'$after='')
{
  return 
PadMessage($message) . ToString($array$style) .
        
" (" count($array) . ")" $after "\n";
}

// Style: 'n' for 'native' (using print_r), 'v' for 'values', 'k' for keys and values
function ToString(&$array$style='v')
{
    if (
$style == 'n')
        return 
print_r($arraytrue);
    else if (
$style == 'v')
        
// For consistency, use same output style than JavaScript
        
return implode(","$array);
    else if (
$style == 'k')
    {
        
// Simplistic! Too bad if we have equal or comma in the strings... ;-)
        
$r '';
        foreach (
$array as $k => $v)
        {
            
$r .= $k "=" $v ", ";
        }
        return 
rtrim($r", ");
    }
    else
        return 
'';
}

function 
ShowBoolean($boolVal)
{
    return 
$boolVal "TRUE" "FALSE";
}

function 
ShowResult($result$message)
{
    echo 
"<h3>" $message "</h3>\n";
    echo 
"<pre>\n";
    echo 
$result "\n";
    echo 
"</pre>\n";
}

function 
StupidFunction($p) { return $p; }
?>