Согласно документации PHP,
Объектные интерфейсы позволяют создавать код, который указывает, какие методы должен реализовать класс, без необходимости определять, как эти методы реализованы.
Следовательно, интерфейс похож на класс с предопределенным методом, к которому все еще нужно обращаться с помощью символа ->.
Однако Интерфейс ArrayAccess обеспечивает доступ к объектам как к массивам. Возможность доступа к объекту как с помощью $object->property, так и $object["property"]
Я не могу понять, как ArrayAccess позволяет изменить синтаксис объекта. Я написал код, чтобы попытаться воспроизвести эффект только одного из методов ArrayAccess, но он выдает ошибку
// Using the PHP ArrayAccess Interface
namespace A {
class myclass implements \ArrayAccess {
public function offsetExists($offset) { return true; }
public function offsetGet($offset) {
// changed behaviour
return $this->{$offset} ?? null;
}
public function offsetSet($offset, $value) {}
public function offsetUnset($offset) {}
}
$myclass = new myclass();
$myclass->access = 'Interface';
echo $myclass['access']; // "Interface"
};
//Trying to implement my own ArrayAccess Interface
namespace B {
interface MyArrayAccess {
public function offsetGet($offset);
}
class myclass implements MyArrayAccess {
public function offsetGet($offset) {
// change behaviour
return $this->{$offset} ?? null;
}
}
$myclass = new myclass();
$myclass->access = 'Interface';
echo $myclass['access']; // Fatal error: Uncaught Error: Cannot use object of type B\myclass as array
}
Пожалуйста, помогите мне объяснить это правильно. Спасибо
«интерфейс подобен классу с предопределенным методом, к которому все еще нужно обращаться с помощью символа ->». Интерфейс также может определять абстрактные методы. Синтаксис PHP, используемый для доступа к материалам внутри классов, не имеет ничего общего с интерфейсами.
ArrayAccess является встроенным, он основан на некоторой внутренней реализации, написанной на C. Интерфейс здесь просто предоставляет функциональность, поэтому вы можете применить ее к своим собственным классам, написанным на PHP.






Вместо того, чтобы говорить, что интерфейс «меняет поведение класса», я бы сказал, что интерфейс упрощает расширение функциональности класса.
Чтобы понять интерфейс как концепцию объектно-ориентированного программирования, мы должны сначала понять, какую проблему он здесь решает.
Интерфейсы являются своего рода контрактом. Это способ добиться утиной печати в PHP. Вы должны думать с точки зрения автора библиотеки, который хочет предоставить функциональность другим. Например,
class Greeter
{
public function greet($person)
{
echo "Hello, {$person->getName()}!\n";
}
}
Чтобы убедиться, что пользователь библиотеки знает, что $person должен иметь getName() метод, вы можете создать класс Person, который имеет getName() метод. Затем используйте Объявление типа, чтобы обнаружить потенциальную ошибку при анализе кода.
class Greeter
{
public function greet(Person $person)
{
echo "Hello, {$person->getName()}!\n";
}
}
class Person
{
public string $name;
public function getName(): string
{
return $this->name;
}
}
Предположим, что есть еще одна библиотека для кормления вещей едой:
class Feeder {
public function feed(Eater $eater, string $food) {
$eater->eat($food);
}
}
class Animal {
private $stomach = [];
public function eat(string $food) {
$stomach = $food;
}
}
Теперь предположим, что пользователь хочет написать класс Pet, который может и есть, и приветствовать. Пользователь не хочет снова писать эти функции только для Pet.
Как написать Pet, чтобы на нем можно было использовать и Greeter, и библиотеку Feeder?
Возможно, что-то вроде этого?
class Pet extends Person, Animal {
}
К сожалению, PHP НЕ поддерживает множественное наследование. Класс может только extend один класс. Приведенный выше код недействителен. Таким образом, в текущей ситуации пользователь может использовать только одну из библиотек.
Также для разных вещей «имя» может быть совершенно другим понятием (например, человек может вернуть как $first_name, так и $last_name с getName()). Для начала может не быть разумной реализации метода getName() по умолчанию в вашем библиотечном классе.
Итак, вы, как автор библиотеки, хотите, чтобы его / ее библиотека была максимально гибкой для пользователя. Что ты можешь сделать?
Интерфейс — это объявление сигнатур методов. Это ярлык для объявления требований к библиотеке без требований к конкретному классу/наследованию.
С интерфейсом вы можете переписать обе библиотеки следующим образом:
Greeter библиотекаclass Greeter {
public function greet(Namer $namer) {
echo "Hello, {$namer->getName()}!\n";
}
}
interface Namer {
public function getName(): string;
}
Feeder библиотекаclass Feeder {
public function feed(Eater $eater, string $food) {
$eater->eat($food);
}
}
interface Eater {
public function eat(string $food);
}
Вместо того, чтобы требовать конкретный класс (или наследование родительского класса), классу разрешено реализовывать несколько интерфейсов. Таким образом, приведенный ниже класс Pet полностью допустим в PHP:
class Pet implements Namer, Eater {
private array $stomach = [];
private string $name = '';
public function __construct(string $name)
{
$this->name = $name;
}
/**
* Implements Namer.
*/
public function getName(): string
{
return $this->name;
}
/**
* Implements Eater.
*/
public function eat(string $food)
{
$this->stomach[] = $food;
}
}
$greeter = new Greeter();
$feeder = new Feeder();
$pet = new Pet('Paul');
$greeter->greet($pet);
$feeder->feed($pet, 'a biscuit');
Теперь объект этого Pet класса может работать как с Greeter библиотекой, так и с Feeder библиотекой.
ArrayAccess?Интерфейс ArrayAccess — это интерфейс, объявленный не сторонними авторами библиотек, а основными авторами PHP. Core PHP Writer обеспечивает еще более глубокую поддержку.
Немного похоже на интерфейс, о котором мы упоминали ранее, PHP предоставляет функцию классу, который ее реализует. Но вместо наших Greeter или Feeder примеров выше, базовый PHP предоставляет Синтаксический сахар классу, который реализует ArrayAccess. Это означает, что вы можете использовать более чистый код для работы с классами, реализующими интерфейс AccessAccess.
В официальном примере
<?php
class Obj implements ArrayAccess {
private $container = array();
public function __construct() {
$this->container = array(
"one" => 1,
"two" => 2,
"three" => 3,
);
}
public function offsetSet($offset, $value) {
if (is_null($offset)) {
$this->container[] = $value;
} else {
$this->container[$offset] = $value;
}
}
public function offsetExists($offset) {
return isset($this->container[$offset]);
}
public function offsetUnset($offset) {
unset($this->container[$offset]);
}
public function offsetGet($offset) {
return isset($this->container[$offset]) ? $this->container[$offset] : null;
}
}
Если вы их реализовали, то вместо этих:
$obj = new Obj;
$obj->offsetSet(10, "hello");
$obj->offsetSet(11, "world");
if ($obj->offsetUnset(12)) {
$obj->offsetUnset(12);
}
echo $obj->offsetGet(11);
Вы можете использовать $obj с синтаксисом, подобным массиву, чтобы сделать ваш код короче:
$obj = new Obj;
$obj[10] = "hello";
$obj[11] = "world";
if (isset($obj[12])) {
unset($obj[12]);
}
echo $obj[11];
когда вы реализуете ArrayAccess, к объекту вашего класса можно получить доступ с помощью оператора доступа к массиву
[]. По своей сути соответствующий метод интерфейса вызывается (по PHP)