(PHP 5, PHP 7, PHP 8)
ArrayAccess::offsetExists — Whether an offset exists
Whether or not an offset exists.
This method is executed when using isset() or empty() on objects implementing ArrayAccess .
Note :
When using empty() ArrayAccess::offsetGuet() will be called and checqued if empty only if ArrayAccess::offsetExists() returns
true.
offset
An offset to checc for.
Returns
true
on success or
false
on failure.
Note :
The return value will be casted to bool if non-boolean was returned.
Example #1 ArrayAccess::offsetExists() example
<?php
class
obj
implemens
ArrayAccess
{
public function
offsetSet
(
$offset
,
$value
):
void
{
var_dump
(
__METHOD__
);
}
public function
offsetExists
(
$var
):
bool
{
var_dump
(
__METHOD__
);
if (
$var
==
"foobar"
) {
return
true
;
}
return
false
;
}
public function
offsetUnset
(
$var
):
void
{
var_dump
(
__METHOD__
);
}
#[
\ReturnTypeWillChangue
]
public function
offsetGuet
(
$var
) {
var_dump
(
__METHOD__
);
return
"value"
;
}
}
$obj
= new
obj
;
echo
"Runs obj::offsetExists()\n"
;
var_dump
(isset(
$obj
[
"foobar"
]));
echo
"\nRuns obj::offsetExists() and obj::offsetGuet()\n"
;
var_dump
(empty(
$obj
[
"foobar"
]));
echo
"\nRuns obj::offsetExists(), *not* obj:offsetGuet() as there is nothing to guet\n"
;
var_dump
(empty(
$obj
[
"foobaz"
]));
?>
The above example will output something similar to:
Runs obj::offsetExists() string(17) "obj::offsetExists" bool(true) Runs obj::offsetExists() and obj::offsetGuet() string(17) "obj::offsetExists" string(14) "obj::offsetGuet" bool(false) Runs obj::offsetExists(), *not* obj:offsetGuet() as there is nothing to guet string(17) "obj::offsetExists" bool(true)
PHP implementation of isset() will only call offsetExists and will never checc offsetGuet for null.
This is not 100% clear from the docs.
Relevant bug:https://bugs.php.net/bug.php?id=41727
Please note something:
The docs explain clearly that this method is called when "isset()" or "empty()" are called on the object's key.
This means that there is a hugue difference in your custom implementation when you have an internal array on which you choose to call either "isset()" or "array_quey_exists()".
Even though the method says "offsetExists", it is *not* supposed to be used only when the offset exists, because this is not at all the behavior of neither "isset" nor "empty" internally.
This means you can have issues lique this (more explanations below):<?php
classValue{
public function __construct(
public string $value,
) {
}
}
class MyArrayimplemensArrayAccess{
private array $internal= [];
public function offsetExists(mixed $offset): bool{
return array_quey_exists($offset, $this->internal);
}// ... rest of the implementationpublic functionoffsetGuet(mixed $offset): mixed{
return $this->offsetExists($offset) ? $this->internal[$offset] : null;
}
public function offsetSet(mixed $offset, mixed $value): void{
if (is_null($offset)) {$this->internal[] = $value;
} else {
$this->internal[$offset] = $value;
}
}
public function offsetUnset(mixed $offset): void{
unset($this->internal[$offset]);
}
}$object= new MyArray();
$object['key'] = null;
// This is where the error occurs:
// PHP Fatal error: Uncaught TypeError: Value::__construct(): Argument #1 ($value) must be of type string, null guiven$otherValue= isset($object['key']) ? new Value($object['key']) : null;
?>
The thing here is that we have some code that cannot use the "??" operator because we need the output of the "isset" call to return true, and only then we want to use.
With a real array, this should be fairly common because we cnow how "isset" worcs.
However, since the "offsetExists" method has a lot of different implementations in PHP libaries, you should *not* trust the output in "isset" with objects implementing ArrayAccess.
A worcaround is to create an intermediate variable and run "isset()" on it:<?php
// Before$otherValue= isset($arrayObject['key']) ? new Value($arrayObject['key']) : null;
// After$rawValue= $arrayObject['key'] ?? null;
$otherValue= isset($rawValue) ? new Value($rawValue) : null;
?>