Call time pass by reference was removed in PHP 5.4. But I have a special case where it seems to be still available in PHP 8 (tried it here: www.w3schools.com):
$myVar = "original";
testFunc([$myVar]);
echo "Variable value: $myVar<br>"; // Output is: "Variable value: original"
testFunc([&$myVar]);
echo "Variable value: $myVar<br>"; // Output is: "Variable value: changed"
testFunc([&$undefinedVar]);
echo "Variable value: $undefinedVar<br>"; // Output is: "Variable value: changed"
testFunc([$undefinedVar_2]);
echo "Variable value: $undefinedVar_2<br>"; // Output is: "Variable value: "
function testFunc( array $arr ) : void
{
if ( !is_array($arr)
|| count($arr) == 0 )
return;
$arr[0] = 'changed';
}
Additionally, this way I can get a C#
like parameter out
functionality.
Maybe I am misunderstanding something.
Question:
How could I identify within "testFunc" if $arr[0]
was passed by reference or normally?
Alternative question (for people who are searching this topic):
Check if variable was passed by reference.
The code by @Foobar pointed me to the right direction. I am using the output of var_dump
to analyze it and create a data structure out of it:
class ReferenceInfo
{
public string $Type;
public bool $IsReference;
/** int, float, double, bool are always initialized with default value */
public bool $IsInitialized;
/** @var ?ReferenceInfo[] */
public ?array $SubItems;
public static function FromVariable( mixed $arr ) : ?ReferenceInfo
{
/** @var ReferenceInfo $rootRefInfo */
$rootRefInfo = NULL;
$varInfoStr = self::varDumpToString($arr);
$varInfoStrArray = preg_split("/\r\n|\n|\r/", $varInfoStr);
$refInfoObjectStack = [];
$curKey = NULL;
foreach ( $varInfoStrArray as $line ) {
$lineTrimmed = trim($line);
$lineTrimmedLen = strlen($lineTrimmed);
if ( $lineTrimmedLen == 0 )
continue;
if ( $lineTrimmed == '}' ) {
array_pop($refInfoObjectStack);
$curKey = NULL;
continue;
}
if ( $lineTrimmed[0] == '[' ) {
// Found array key
$bracketEndPos = strpos($lineTrimmed, ']');
if ( $bracketEndPos === false )
return NULL;
$keyName = self::convertToRealType(substr($lineTrimmed, 1, $bracketEndPos - 1));
$curKey = $keyName;
continue;
}
$parenPos = strpos($lineTrimmed, '(');
if ( $parenPos === false ) {
// Must be a NULL type
$parenPos = $lineTrimmedLen;
}
$type = substr($lineTrimmed, 0, $parenPos);
$isInitialized = true;
if ( $type == 'uninitialized' ) {
$parenEndPos = strpos($lineTrimmed, ')', $parenPos);
if ( $parenEndPos === false )
return NULL;
$type = substr($lineTrimmed, $parenPos + 1, $parenEndPos - $parenPos - 1);
$isInitialized = false;
}
$refInfoObj = new ReferenceInfo();
$refInfoObj->IsReference = str_starts_with($type, '&');
$refInfoObj->IsInitialized = $isInitialized;
$refInfoObj->Type = substr($type, $refInfoObj->IsReference ? 1 : 0);
if ( $rootRefInfo == NULL ) {
$rootRefInfo = $refInfoObj;
} else {
$refInfoObjectStack[count($refInfoObjectStack) - 1]->SubItems[$curKey] = $refInfoObj;
}
if ( $refInfoObj->Type == 'array'
|| $refInfoObj->Type == 'object' ) {
$refInfoObj->SubItems = [];
$refInfoObjectStack[] = $refInfoObj;
}
}
return $rootRefInfo;
}
private static function convertToRealType( string $keyName ) : float|int|string
{
if ( $keyName[0] == '"' ) {
$keyName = substr($keyName, 1, strlen($keyName) - 2);
} else if ( is_numeric($keyName) ) {
if ( str_contains($keyName, '.') )
$keyName = doubleval($keyName);
else
$keyName = intval($keyName);
}
return $keyName;
}
private static function varDumpToString( mixed $var ) : string
{
ob_start();
var_dump($var);
return ob_get_clean();
}
}