oop — без форвардного объявления в PHP мне не повезло в этом случае?

ОБНОВЛЕНИЕ: То, что я отправил, было неточным. Я пытался свести проблему к простейшему случаю, но упустил из виду кое-что важное. Это мой оригинальный пост:

Учитывая следующий код

 Class B extends A {
...
}

Class A {
...
}

Позиция А в файле, видимо, важна, потому что я получу
Ошибки «Класс А не найден», если я не переместлю А выше В внутри файла.
Это работает в резком контрасте со всем остальным положением
независимый в PHP. Это неудобно, потому что если класс А
особенно большой и вовлеченный, и я хочу только ответственных людей
для поддержания кода, чтобы действительно беспокоиться о различиях
между классом A и классами B-Z, которые расширяют A, они все еще должны
прокрутите мимо A, как работает мой php.

Единственное решение, которое я вижу, — чтобы код был разборчивым, поскольку
вперед декларации, это переместить A в совершенно другой файл
и require_once этот файл. Я открыт для других идей, или особенно
люди говорят мне, что я просто неправильно настроил свою систему
/ я делаю что-то еще не так с моей стороны.

Я использую 5.5.18 через lighttpd и модуль php-fpm. Если будет
помочь я могу включить php_info на моем сервере, и вы можете взглянуть на мой
конфигурационные файлы или выбросить вещи в pastebin по запросу.

Однако, когда я оглянулся назад на мой код и журналы ошибок, я фактически должен был сделать что-то еще, чтобы вызвать ошибку:

class A extends B implements C {
}

interface C {
}

class B implements C {
}

Сообщение об ошибке исчезает, когда B больше не реализует C. Таким образом, проблема может заключаться в моем собственном понимании ориентации объекта PHP.

Я оставлю этот вопрос, потому что сообщение об ошибке, которое я получил, по-прежнему вводит в заблуждение. Но я должен был быть более осторожным, публикуя свой пример. Извиняюсь.

2

Решение

PHP поддерживает прямое объявление классов (а также функций). Следующий код прекрасно работает на PHP 5:

<?php
class B extends A {
public function __construct(){
echo A::property;
}
}
class A {
const property = "I am a const!".PHP_EOL;
}
$b = new B();

выход:

I am a const!

Это тоже будет работать:

<?php
class A {
const property = "I am a const!".PHP_EOL;
public function __construct(){
$b = new B();
}
}
class B extends A {
public function __construct(){
echo A::property;
}
}
$a = new A();

выход:

I am a const!

Что не работает, так это создание классов перед определением. Например:

<?php
$b = new B();
class B extends A {
public function __construct(){
echo A::property;
}
}
class A {
const property = "I am a prop!".PHP_EOL;
}

выход:

PHP Fatal error:  Class 'B' not found in /root/test.php on line 2

В двух словах, даже если PHP интерпретируется, вы должны понимать, что ваш скрипт компилируется (во время выполнения), а затем выполняется.

Это означает: компилятор читает определения, затем код выполняется. Порядок определений не имеет значения (на самом деле это имеет значение, но не таким образом), и вы можете смешивать определения и выполнение, если все, что вы выполняете, определено в момент его выполнения / создания экземпляра.

Если все остальное в порядке, возможно, вам следует проверить свой код на предмет определения пространств имен или ошибок автозагрузчика, как указано в комментариях. Это может быть реальной причиной вашей проблемы.

4

Другие решения

В PHP есть концепция автозагрузки классов по запросу — взгляните: http://php.net/manual/en/language.oop5.autoload.php

1

Частичный ответ: я уменьшил проблему до 4 строк кода:

$lo_comp = new CComparer;
interface IComparer { }
class CComparer   implements  IComparer
{ }

Этот код завершается с ошибкой «Класс ‘CComparer’ not found» Uncaught Error, но любой из следующих исправлений устраняет ошибку:

  1. Закомментируем два слова «реализует IComparer»
  2. Превращение IComparer в класс (или абстрактный класс), а не в интерфейс
  3. Выполнение экземпляра ПОСЛЕ определения CComparer (но недостаточно переместить его между определениями IComparer и CComparer)

Поведение такое же на Endora.cz Freehosting, http://sandbox.onlinephpfunctions.com/ или же http://eval.in — оба в PHP 5 или 7.


Я рад, что этот PHP может «видеть вперед» определение функций и классов, если они не находятся внутри блока if или чего-то подобного. Когда он работает даже для классов, производных от (абстрактных или конкретных) суперклассов, почему он не работает для классов, реализующих интерфейс (даже «уже увиденный» интерфейс, как во второй половине пункта 3)?

Это намеренно или я обнаружил ошибку в PHP?

Так что я думаю, что не совсем точно, как предполагает Джессика Пеннелл, что класс, реализующий интерфейс, должен быть «листовым» классом.

Спасибо

Павел

1

Поэтому я все еще пытаюсь выяснить, в чем именно заключается проблема, но я нашел (благодаря elcodedocle и Wrikken) схему, которая поможет избежать проблемы, с которой я столкнулся.

Короче говоря, если у вас есть класс, который реализует интерфейс, он, очевидно, должен быть «листовым» классом, и если вы попытаетесь его расширить, в любом случае из моих экспериментов вы получите загадочную ошибку «класс не найден». Таким образом, решение состоит в том, чтобы ключевое слово «Implements» появлялось только на каждом дочернем элементе класса, для которого вы хотите реализовать интерфейс, даже если родительский элемент выполняет и выполняет все те же обещания.

0