Page Menu
Home
WickedGov Phorge
Search
Configure Global Search
Log In
Files
F4139981
Test.php
No One
Temporary
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
25 KB
Referenced Files
None
Subscribers
None
Test.php
View Options
<?php
declare
(
strict_types
=
1
);
/*
* This file is part of PHPUnit.
*
* (c) Sebastian Bergmann <sebastian@phpunit.de>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace
PHPUnit\Util
;
use
const
PHP_OS
;
use
const
PHP_VERSION
;
use
function
addcslashes
;
use
function
array_flip
;
use
function
array_key_exists
;
use
function
array_merge
;
use
function
array_unique
;
use
function
array_unshift
;
use
function
class_exists
;
use
function
count
;
use
function
explode
;
use
function
extension_loaded
;
use
function
function_exists
;
use
function
get_class
;
use
function
ini_get
;
use
function
interface_exists
;
use
function
is_array
;
use
function
is_int
;
use
function
method_exists
;
use
function
phpversion
;
use
function
preg_match
;
use
function
preg_replace
;
use
function
sprintf
;
use
function
strncmp
;
use
function
strpos
;
use
function
strtolower
;
use
function
trim
;
use
function
version_compare
;
use
PHPUnit\Framework\CodeCoverageException
;
use
PHPUnit\Framework\ExecutionOrderDependency
;
use
PHPUnit\Framework\InvalidCoversTargetException
;
use
PHPUnit\Framework\SelfDescribing
;
use
PHPUnit\Framework\TestCase
;
use
PHPUnit\Framework\Warning
;
use
PHPUnit\Runner\Version
;
use
PHPUnit\Util\Annotation\Registry
;
use
ReflectionClass
;
use
ReflectionException
;
use
ReflectionMethod
;
use
SebastianBergmann\CodeUnit\CodeUnitCollection
;
use
SebastianBergmann\CodeUnit\InvalidCodeUnitException
;
use
SebastianBergmann\CodeUnit\Mapper
;
use
SebastianBergmann\Environment\OperatingSystem
;
use
SebastianBergmann\RecursionContext\InvalidArgumentException
;
/**
* @internal This class is not covered by the backward compatibility promise for PHPUnit
*/
final
class
Test
{
/**
* @var int
*/
public
const
UNKNOWN
=
-
1
;
/**
* @var int
*/
public
const
SMALL
=
0
;
/**
* @var int
*/
public
const
MEDIUM
=
1
;
/**
* @var int
*/
public
const
LARGE
=
2
;
/**
* @var array
*/
private
static
$hookMethods
=
[];
/**
* @throws InvalidArgumentException
*/
public
static
function
describe
(
\PHPUnit\Framework\Test
$test
):
array
{
if
(
$test
instanceof
TestCase
)
{
return
[
get_class
(
$test
),
$test
->
getName
()];
}
if
(
$test
instanceof
SelfDescribing
)
{
return
[
''
,
$test
->
toString
()];
}
return
[
''
,
get_class
(
$test
)];
}
public
static
function
describeAsString
(
\PHPUnit\Framework\Test
$test
):
string
{
if
(
$test
instanceof
SelfDescribing
)
{
return
$test
->
toString
();
}
return
get_class
(
$test
);
}
/**
* @throws CodeCoverageException
*
* @return array|bool
*
* @psalm-param class-string $className
*/
public
static
function
getLinesToBeCovered
(
string
$className
,
string
$methodName
)
{
$annotations
=
self
::
parseTestMethodAnnotations
(
$className
,
$methodName
,
);
if
(!
self
::
shouldCoversAnnotationBeUsed
(
$annotations
))
{
return
false
;
}
return
self
::
getLinesToBeCoveredOrUsed
(
$className
,
$methodName
,
'covers'
);
}
/**
* Returns lines of code specified with the @uses annotation.
*
* @throws CodeCoverageException
*
* @psalm-param class-string $className
*/
public
static
function
getLinesToBeUsed
(
string
$className
,
string
$methodName
):
array
{
return
self
::
getLinesToBeCoveredOrUsed
(
$className
,
$methodName
,
'uses'
);
}
public
static
function
requiresCodeCoverageDataCollection
(
TestCase
$test
):
bool
{
$annotations
=
self
::
parseTestMethodAnnotations
(
get_class
(
$test
),
$test
->
getName
(
false
),
);
// If there is no @covers annotation but a @coversNothing annotation on
// the test method then code coverage data does not need to be collected
if
(
isset
(
$annotations
[
'method'
][
'coversNothing'
]))
{
// @see https://github.com/sebastianbergmann/phpunit/issues/4947#issuecomment-1084480950
// return false;
}
// If there is at least one @covers annotation then
// code coverage data needs to be collected
if
(
isset
(
$annotations
[
'method'
][
'covers'
]))
{
return
true
;
}
// If there is no @covers annotation but a @coversNothing annotation
// then code coverage data does not need to be collected
if
(
isset
(
$annotations
[
'class'
][
'coversNothing'
]))
{
// @see https://github.com/sebastianbergmann/phpunit/issues/4947#issuecomment-1084480950
// return false;
}
// If there is no @coversNothing annotation then
// code coverage data may be collected
return
true
;
}
/**
* @throws Exception
*
* @psalm-param class-string $className
*/
public
static
function
getRequirements
(
string
$className
,
string
$methodName
):
array
{
return
self
::
mergeArraysRecursively
(
Registry
::
getInstance
()->
forClassName
(
$className
)->
requirements
(),
Registry
::
getInstance
()->
forMethod
(
$className
,
$methodName
)->
requirements
(),
);
}
/**
* Returns the missing requirements for a test.
*
* @throws Exception
* @throws Warning
*
* @psalm-param class-string $className
*/
public
static
function
getMissingRequirements
(
string
$className
,
string
$methodName
):
array
{
$required
=
self
::
getRequirements
(
$className
,
$methodName
);
$missing
=
[];
$hint
=
null
;
if
(!
empty
(
$required
[
'PHP'
]))
{
$operator
=
new
VersionComparisonOperator
(
empty
(
$required
[
'PHP'
][
'operator'
])
?
'>='
:
$required
[
'PHP'
][
'operator'
]);
if
(!
version_compare
(
PHP_VERSION
,
$required
[
'PHP'
][
'version'
],
$operator
->
asString
()))
{
$missing
[]
=
sprintf
(
'PHP %s %s is required.'
,
$operator
->
asString
(),
$required
[
'PHP'
][
'version'
]);
$hint
=
'PHP'
;
}
}
elseif
(!
empty
(
$required
[
'PHP_constraint'
]))
{
$version
=
new
\PharIo\Version\Version
(
self
::
sanitizeVersionNumber
(
PHP_VERSION
));
if
(!
$required
[
'PHP_constraint'
][
'constraint'
]->
complies
(
$version
))
{
$missing
[]
=
sprintf
(
'PHP version does not match the required constraint %s.'
,
$required
[
'PHP_constraint'
][
'constraint'
]->
asString
(),
);
$hint
=
'PHP_constraint'
;
}
}
if
(!
empty
(
$required
[
'PHPUnit'
]))
{
$phpunitVersion
=
Version
::
id
();
$operator
=
new
VersionComparisonOperator
(
empty
(
$required
[
'PHPUnit'
][
'operator'
])
?
'>='
:
$required
[
'PHPUnit'
][
'operator'
]);
if
(!
version_compare
(
$phpunitVersion
,
$required
[
'PHPUnit'
][
'version'
],
$operator
->
asString
()))
{
$missing
[]
=
sprintf
(
'PHPUnit %s %s is required.'
,
$operator
->
asString
(),
$required
[
'PHPUnit'
][
'version'
]);
$hint
=
$hint
??
'PHPUnit'
;
}
}
elseif
(!
empty
(
$required
[
'PHPUnit_constraint'
]))
{
$phpunitVersion
=
new
\PharIo\Version\Version
(
self
::
sanitizeVersionNumber
(
Version
::
id
()));
if
(!
$required
[
'PHPUnit_constraint'
][
'constraint'
]->
complies
(
$phpunitVersion
))
{
$missing
[]
=
sprintf
(
'PHPUnit version does not match the required constraint %s.'
,
$required
[
'PHPUnit_constraint'
][
'constraint'
]->
asString
(),
);
$hint
=
$hint
??
'PHPUnit_constraint'
;
}
}
if
(!
empty
(
$required
[
'OSFAMILY'
])
&&
$required
[
'OSFAMILY'
]
!==
(
new
OperatingSystem
)->
getFamily
())
{
$missing
[]
=
sprintf
(
'Operating system %s is required.'
,
$required
[
'OSFAMILY'
]);
$hint
=
$hint
??
'OSFAMILY'
;
}
if
(!
empty
(
$required
[
'OS'
]))
{
$requiredOsPattern
=
sprintf
(
'/%s/i'
,
addcslashes
(
$required
[
'OS'
],
'/'
));
if
(!
preg_match
(
$requiredOsPattern
,
PHP_OS
))
{
$missing
[]
=
sprintf
(
'Operating system matching %s is required.'
,
$requiredOsPattern
);
$hint
=
$hint
??
'OS'
;
}
}
if
(!
empty
(
$required
[
'functions'
]))
{
foreach
(
$required
[
'functions'
]
as
$function
)
{
$pieces
=
explode
(
'::'
,
$function
);
if
(
count
(
$pieces
)
===
2
&&
class_exists
(
$pieces
[
0
])
&&
method_exists
(
$pieces
[
0
],
$pieces
[
1
]))
{
continue
;
}
if
(
function_exists
(
$function
))
{
continue
;
}
$missing
[]
=
sprintf
(
'Function %s is required.'
,
$function
);
$hint
=
$hint
??
'function_'
.
$function
;
}
}
if
(!
empty
(
$required
[
'setting'
]))
{
foreach
(
$required
[
'setting'
]
as
$setting
=>
$value
)
{
if
(
ini_get
(
$setting
)
!==
$value
)
{
$missing
[]
=
sprintf
(
'Setting "%s" must be "%s".'
,
$setting
,
$value
);
$hint
=
$hint
??
'__SETTING_'
.
$setting
;
}
}
}
if
(!
empty
(
$required
[
'extensions'
]))
{
foreach
(
$required
[
'extensions'
]
as
$extension
)
{
if
(
isset
(
$required
[
'extension_versions'
][
$extension
]))
{
continue
;
}
if
(!
extension_loaded
(
$extension
))
{
$missing
[]
=
sprintf
(
'Extension %s is required.'
,
$extension
);
$hint
=
$hint
??
'extension_'
.
$extension
;
}
}
}
if
(!
empty
(
$required
[
'extension_versions'
]))
{
foreach
(
$required
[
'extension_versions'
]
as
$extension
=>
$req
)
{
$actualVersion
=
phpversion
(
$extension
);
$operator
=
new
VersionComparisonOperator
(
empty
(
$req
[
'operator'
])
?
'>='
:
$req
[
'operator'
]);
if
(
$actualVersion
===
false
||
!
version_compare
(
$actualVersion
,
$req
[
'version'
],
$operator
->
asString
()))
{
$missing
[]
=
sprintf
(
'Extension %s %s %s is required.'
,
$extension
,
$operator
->
asString
(),
$req
[
'version'
]);
$hint
=
$hint
??
'extension_'
.
$extension
;
}
}
}
if
(
$hint
&&
isset
(
$required
[
'__OFFSET'
]))
{
array_unshift
(
$missing
,
'__OFFSET_FILE='
.
$required
[
'__OFFSET'
][
'__FILE'
]);
array_unshift
(
$missing
,
'__OFFSET_LINE='
.
(
$required
[
'__OFFSET'
][
$hint
]
??
1
));
}
return
$missing
;
}
/**
* Returns the provided data for a method.
*
* @throws Exception
*
* @psalm-param class-string $className
*/
public
static
function
getProvidedData
(
string
$className
,
string
$methodName
):
?
array
{
return
Registry
::
getInstance
()->
forMethod
(
$className
,
$methodName
)->
getProvidedData
();
}
/**
* @psalm-param class-string $className
*/
public
static
function
parseTestMethodAnnotations
(
string
$className
,
?
string
$methodName
=
null
):
array
{
$registry
=
Registry
::
getInstance
();
if
(
$methodName
!==
null
)
{
try
{
return
[
'method'
=>
$registry
->
forMethod
(
$className
,
$methodName
)->
symbolAnnotations
(),
'class'
=>
$registry
->
forClassName
(
$className
)->
symbolAnnotations
(),
];
}
catch
(
Exception
$methodNotFound
)
{
// ignored
}
}
return
[
'method'
=>
null
,
'class'
=>
$registry
->
forClassName
(
$className
)->
symbolAnnotations
(),
];
}
/**
* @psalm-param class-string $className
*/
public
static
function
getInlineAnnotations
(
string
$className
,
string
$methodName
):
array
{
return
Registry
::
getInstance
()->
forMethod
(
$className
,
$methodName
)->
getInlineAnnotations
();
}
/** @psalm-param class-string $className */
public
static
function
getBackupSettings
(
string
$className
,
string
$methodName
):
array
{
return
[
'backupGlobals'
=>
self
::
getBooleanAnnotationSetting
(
$className
,
$methodName
,
'backupGlobals'
,
),
'backupStaticAttributes'
=>
self
::
getBooleanAnnotationSetting
(
$className
,
$methodName
,
'backupStaticAttributes'
,
),
];
}
/**
* @psalm-param class-string $className
*
* @return ExecutionOrderDependency[]
*/
public
static
function
getDependencies
(
string
$className
,
string
$methodName
):
array
{
$annotations
=
self
::
parseTestMethodAnnotations
(
$className
,
$methodName
,
);
$dependsAnnotations
=
$annotations
[
'class'
][
'depends'
]
??
[];
if
(
isset
(
$annotations
[
'method'
][
'depends'
]))
{
$dependsAnnotations
=
array_merge
(
$dependsAnnotations
,
$annotations
[
'method'
][
'depends'
],
);
}
// Normalize dependency name to className::methodName
$dependencies
=
[];
foreach
(
$dependsAnnotations
as
$value
)
{
$dependencies
[]
=
ExecutionOrderDependency
::
createFromDependsAnnotation
(
$className
,
$value
);
}
return
array_unique
(
$dependencies
);
}
/** @psalm-param class-string $className */
public
static
function
getGroups
(
string
$className
,
?
string
$methodName
=
''
):
array
{
$annotations
=
self
::
parseTestMethodAnnotations
(
$className
,
$methodName
,
);
$groups
=
[];
if
(
isset
(
$annotations
[
'method'
][
'author'
]))
{
$groups
[]
=
$annotations
[
'method'
][
'author'
];
}
elseif
(
isset
(
$annotations
[
'class'
][
'author'
]))
{
$groups
[]
=
$annotations
[
'class'
][
'author'
];
}
if
(
isset
(
$annotations
[
'class'
][
'group'
]))
{
$groups
[]
=
$annotations
[
'class'
][
'group'
];
}
if
(
isset
(
$annotations
[
'method'
][
'group'
]))
{
$groups
[]
=
$annotations
[
'method'
][
'group'
];
}
if
(
isset
(
$annotations
[
'class'
][
'ticket'
]))
{
$groups
[]
=
$annotations
[
'class'
][
'ticket'
];
}
if
(
isset
(
$annotations
[
'method'
][
'ticket'
]))
{
$groups
[]
=
$annotations
[
'method'
][
'ticket'
];
}
foreach
([
'method'
,
'class'
]
as
$element
)
{
foreach
([
'small'
,
'medium'
,
'large'
]
as
$size
)
{
if
(
isset
(
$annotations
[
$element
][
$size
]))
{
$groups
[]
=
[
$size
];
break
2
;
}
}
}
foreach
([
'method'
,
'class'
]
as
$element
)
{
if
(
isset
(
$annotations
[
$element
][
'covers'
]))
{
foreach
(
$annotations
[
$element
][
'covers'
]
as
$coversTarget
)
{
$groups
[]
=
[
'__phpunit_covers_'
.
self
::
canonicalizeName
(
$coversTarget
)];
}
}
if
(
isset
(
$annotations
[
$element
][
'uses'
]))
{
foreach
(
$annotations
[
$element
][
'uses'
]
as
$usesTarget
)
{
$groups
[]
=
[
'__phpunit_uses_'
.
self
::
canonicalizeName
(
$usesTarget
)];
}
}
}
return
array_unique
(
array_merge
([],
...
$groups
));
}
/** @psalm-param class-string $className */
public
static
function
getSize
(
string
$className
,
?
string
$methodName
):
int
{
$groups
=
array_flip
(
self
::
getGroups
(
$className
,
$methodName
));
if
(
isset
(
$groups
[
'large'
]))
{
return
self
::
LARGE
;
}
if
(
isset
(
$groups
[
'medium'
]))
{
return
self
::
MEDIUM
;
}
if
(
isset
(
$groups
[
'small'
]))
{
return
self
::
SMALL
;
}
return
self
::
UNKNOWN
;
}
/** @psalm-param class-string $className */
public
static
function
getProcessIsolationSettings
(
string
$className
,
string
$methodName
):
bool
{
$annotations
=
self
::
parseTestMethodAnnotations
(
$className
,
$methodName
,
);
return
isset
(
$annotations
[
'class'
][
'runTestsInSeparateProcesses'
])
||
isset
(
$annotations
[
'method'
][
'runInSeparateProcess'
]);
}
/** @psalm-param class-string $className */
public
static
function
getClassProcessIsolationSettings
(
string
$className
,
string
$methodName
):
bool
{
$annotations
=
self
::
parseTestMethodAnnotations
(
$className
,
$methodName
,
);
return
isset
(
$annotations
[
'class'
][
'runClassInSeparateProcess'
]);
}
/** @psalm-param class-string $className */
public
static
function
getPreserveGlobalStateSettings
(
string
$className
,
string
$methodName
):
?
bool
{
return
self
::
getBooleanAnnotationSetting
(
$className
,
$methodName
,
'preserveGlobalState'
,
);
}
/** @psalm-param class-string $className */
public
static
function
getHookMethods
(
string
$className
):
array
{
if
(!
class_exists
(
$className
,
false
))
{
return
self
::
emptyHookMethodsArray
();
}
if
(!
isset
(
self
::
$hookMethods
[
$className
]))
{
self
::
$hookMethods
[
$className
]
=
self
::
emptyHookMethodsArray
();
try
{
foreach
((
new
Reflection
)->
methodsInTestClass
(
new
ReflectionClass
(
$className
))
as
$method
)
{
$docBlock
=
Registry
::
getInstance
()->
forMethod
(
$className
,
$method
->
getName
());
if
(
$method
->
isStatic
())
{
if
(
$docBlock
->
isHookToBeExecutedBeforeClass
())
{
array_unshift
(
self
::
$hookMethods
[
$className
][
'beforeClass'
],
$method
->
getName
(),
);
}
if
(
$docBlock
->
isHookToBeExecutedAfterClass
())
{
self
::
$hookMethods
[
$className
][
'afterClass'
][]
=
$method
->
getName
();
}
}
if
(
$docBlock
->
isToBeExecutedBeforeTest
())
{
array_unshift
(
self
::
$hookMethods
[
$className
][
'before'
],
$method
->
getName
(),
);
}
if
(
$docBlock
->
isToBeExecutedAsPreCondition
())
{
array_unshift
(
self
::
$hookMethods
[
$className
][
'preCondition'
],
$method
->
getName
(),
);
}
if
(
$docBlock
->
isToBeExecutedAsPostCondition
())
{
self
::
$hookMethods
[
$className
][
'postCondition'
][]
=
$method
->
getName
();
}
if
(
$docBlock
->
isToBeExecutedAfterTest
())
{
self
::
$hookMethods
[
$className
][
'after'
][]
=
$method
->
getName
();
}
}
}
catch
(
ReflectionException
$e
)
{
}
}
return
self
::
$hookMethods
[
$className
];
}
public
static
function
isTestMethod
(
ReflectionMethod
$method
):
bool
{
if
(!
$method
->
isPublic
())
{
return
false
;
}
if
(
strpos
(
$method
->
getName
(),
'test'
)
===
0
)
{
return
true
;
}
return
array_key_exists
(
'test'
,
Registry
::
getInstance
()->
forMethod
(
$method
->
getDeclaringClass
()->
getName
(),
$method
->
getName
(),
)
->
symbolAnnotations
(),
);
}
/**
* @throws CodeCoverageException
*
* @psalm-param class-string $className
*/
private
static
function
getLinesToBeCoveredOrUsed
(
string
$className
,
string
$methodName
,
string
$mode
):
array
{
$annotations
=
self
::
parseTestMethodAnnotations
(
$className
,
$methodName
,
);
$classShortcut
=
null
;
if
(!
empty
(
$annotations
[
'class'
][
$mode
.
'DefaultClass'
]))
{
if
(
count
(
$annotations
[
'class'
][
$mode
.
'DefaultClass'
])
>
1
)
{
throw
new
CodeCoverageException
(
sprintf
(
'More than one @%sClass annotation in class or interface "%s".'
,
$mode
,
$className
,
),
);
}
$classShortcut
=
$annotations
[
'class'
][
$mode
.
'DefaultClass'
][
0
];
}
$list
=
$annotations
[
'class'
][
$mode
]
??
[];
if
(
isset
(
$annotations
[
'method'
][
$mode
]))
{
$list
=
array_merge
(
$list
,
$annotations
[
'method'
][
$mode
]);
}
$codeUnits
=
CodeUnitCollection
::
fromArray
([]);
$mapper
=
new
Mapper
;
foreach
(
array_unique
(
$list
)
as
$element
)
{
if
(
$classShortcut
&&
strncmp
(
$element
,
'::'
,
2
)
===
0
)
{
$element
=
$classShortcut
.
$element
;
}
$element
=
preg_replace
(
'/[
\s
()]+$/'
,
''
,
$element
);
$element
=
explode
(
' '
,
$element
);
$element
=
$element
[
0
];
if
(
$mode
===
'covers'
&&
interface_exists
(
$element
))
{
throw
new
InvalidCoversTargetException
(
sprintf
(
'Trying to @cover interface "%s".'
,
$element
,
),
);
}
try
{
$codeUnits
=
$codeUnits
->
mergeWith
(
$mapper
->
stringToCodeUnits
(
$element
));
}
catch
(
InvalidCodeUnitException
$e
)
{
throw
new
InvalidCoversTargetException
(
sprintf
(
'"@%s %s" is invalid'
,
$mode
,
$element
,
),
$e
->
getCode
(),
$e
,
);
}
}
return
$mapper
->
codeUnitsToSourceLines
(
$codeUnits
);
}
private
static
function
emptyHookMethodsArray
():
array
{
return
[
'beforeClass'
=>
[
'setUpBeforeClass'
],
'before'
=>
[
'setUp'
],
'preCondition'
=>
[
'assertPreConditions'
],
'postCondition'
=>
[
'assertPostConditions'
],
'after'
=>
[
'tearDown'
],
'afterClass'
=>
[
'tearDownAfterClass'
],
];
}
/** @psalm-param class-string $className */
private
static
function
getBooleanAnnotationSetting
(
string
$className
,
?
string
$methodName
,
string
$settingName
):
?
bool
{
$annotations
=
self
::
parseTestMethodAnnotations
(
$className
,
$methodName
,
);
if
(
isset
(
$annotations
[
'method'
][
$settingName
]))
{
if
(
$annotations
[
'method'
][
$settingName
][
0
]
===
'enabled'
)
{
return
true
;
}
if
(
$annotations
[
'method'
][
$settingName
][
0
]
===
'disabled'
)
{
return
false
;
}
}
if
(
isset
(
$annotations
[
'class'
][
$settingName
]))
{
if
(
$annotations
[
'class'
][
$settingName
][
0
]
===
'enabled'
)
{
return
true
;
}
if
(
$annotations
[
'class'
][
$settingName
][
0
]
===
'disabled'
)
{
return
false
;
}
}
return
null
;
}
/**
* Trims any extensions from version string that follows after
* the <major>.<minor>[.<patch>] format.
*/
private
static
function
sanitizeVersionNumber
(
string
$version
)
{
return
preg_replace
(
'/^(
\d
+
\.\d
+(?:.
\d
+)?).*$/'
,
'$1'
,
$version
,
);
}
private
static
function
shouldCoversAnnotationBeUsed
(
array
$annotations
):
bool
{
if
(
isset
(
$annotations
[
'method'
][
'coversNothing'
]))
{
return
false
;
}
if
(
isset
(
$annotations
[
'method'
][
'covers'
]))
{
return
true
;
}
if
(
isset
(
$annotations
[
'class'
][
'coversNothing'
]))
{
return
false
;
}
return
true
;
}
/**
* Merge two arrays together.
*
* If an integer key exists in both arrays and preserveNumericKeys is false, the value
* from the second array will be appended to the first array. If both values are arrays, they
* are merged together, else the value of the second array overwrites the one of the first array.
*
* This implementation is copied from https://github.com/zendframework/zend-stdlib/blob/76b653c5e99b40eccf5966e3122c90615134ae46/src/ArrayUtils.php
*
* Zend Framework (http://framework.zend.com/)
*
* @see http://github.com/zendframework/zf2 for the canonical source repository
*
* @copyright Copyright (c) 2005-2015 Zend Technologies USA Inc. (http://www.zend.com)
* @license http://framework.zend.com/license/new-bsd New BSD License
*/
private
static
function
mergeArraysRecursively
(
array
$a
,
array
$b
):
array
{
foreach
(
$b
as
$key
=>
$value
)
{
if
(
array_key_exists
(
$key
,
$a
))
{
if
(
is_int
(
$key
))
{
$a
[]
=
$value
;
}
elseif
(
is_array
(
$value
)
&&
is_array
(
$a
[
$key
]))
{
$a
[
$key
]
=
self
::
mergeArraysRecursively
(
$a
[
$key
],
$value
);
}
else
{
$a
[
$key
]
=
$value
;
}
}
else
{
$a
[
$key
]
=
$value
;
}
}
return
$a
;
}
private
static
function
canonicalizeName
(
string
$name
):
string
{
return
strtolower
(
trim
(
$name
,
'
\\
'
));
}
}
File Metadata
Details
Attached
Mime Type
text/x-php
Expires
Wed, Aug 19, 15:18 (3 w, 5 d ago)
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
66/49/db8a81920bcb1caeb7128b158411
Default Alt Text
Test.php (25 KB)
Attached To
Mode
rMWPROD MediaWiki Production
Attached
Detach File
Event Timeline
Log In to Comment