Для PHPer ООП является незаменимым мышлением при разработке, но много ли вы знаете о лежащей в основе реализации классов и объектов PHP? С идеей знать это и знать почему, давайте вместе найдем ответ~
Базовую реализацию класса можно рассматривать как набор знаний о переменных, функциях и т. д., о которых мы говорили ранее. Поэтому студентам, которые хотят разобраться глубже, стоит ознакомиться с моими предыдущими статьями о введении переменных и функций.
структура данных класса
Будь то общий класс, абстрактный класс или интерфейс, он хранится в унифицированной структуре, и этот класс добавляется в глобальный список классов при генерации промежуточного кода. Конечно, именно в это время имя класса будет использоваться для определения того, существует ли класс уже.Если он существует, добавление не удастся.
struct _zend_class_entry {
char type; // 和函数一样,类被拆分为两种类型:ZEND_INTERNAL_CLASS 内部类型和ZEND_USER_CLASS 用户自定义类型
char *name;// 类名称
zend_uint name_length; // 即sizeof(name) - 1
struct _zend_class_entry *parent; // 继承的父类
int refcount; // 引用数
zend_bool constants_updated;
zend_uint ce_flags; //类的类型,在编译阶段被区分是普通类,接口,抽象类
HashTable function_table; // 静态类方法和普通类方法存放集合
HashTable default_properties; // 默认属性存放集合
HashTable properties_info; // 属性信息存放集合
HashTable default_static_members;// 类本身所具有的静态变量存放集合
HashTable *static_members; // type == ZEND_USER_CLASS时,取&default_static_members;
// type == ZEND_INTERAL_CLASS时,设为NULL
HashTable constants_table; // 常量存放集合
struct _zend_function_entry *builtin_functions;// 方法定义入口
/* 魔术方法 */
//所有魔术方法单独存放,初始化时被设置为null
union _zend_function *constructor;
union _zend_function *destructor;
union _zend_function *clone;
union _zend_function *__get;
union _zend_function *__set;
union _zend_function *__unset;
union _zend_function *__isset;
union _zend_function *__call;
union _zend_function *__tostring;
union _zend_function *serialize_func;
union _zend_function *unserialize_func;
zend_class_iterator_funcs iterator_funcs;// 迭代
/* 类句柄 */
zend_object_value (*create_object)(zend_class_entry *class_type TSRMLS_DC);
zend_object_iterator *(*get_iterator)(zend_class_entry *ce, zval *object,
intby_ref TSRMLS_DC);
/* 类声明的接口 */
int(*interface_gets_implemented)(zend_class_entry *iface,
zend_class_entry *class_type TSRMLS_DC);
/* 序列化回调函数指针 */
int(*serialize)(zval *object, unsignedchar**buffer, zend_uint *buf_len,
zend_serialize_data *data TSRMLS_DC);
int(*unserialize)(zval **object, zend_class_entry *ce, constunsignedchar*buf,
zend_uint buf_len, zend_unserialize_data *data TSRMLS_DC);
zend_class_entry **interfaces; // 类实现的接口
zend_uint num_interfaces; // 类实现的接口数
char *filename; // 类的存放文件地址 绝对地址
zend_uint line_start; // 类定义的开始行
zend_uint line_end; // 类定义的结束行
char *doc_comment;
zend_uint doc_comment_len;
struct _zend_module_entry *module; // 类所在的模块入口:EG(current_module)
};
Как видно из приведенного выше кода, переменные-члены и методы-члены класса хранятся в своих соответствующих структурах, и структура данных структуры точно такая же, как структура данных переменных и функций, описанных ранее, за исключением того, что скомпилированные переменные-члены и методы-члены хранятся только в структуре класса
генерация объекта
Все мы знаем, что объекты создаются новыми, но снизу вверх генерация объектов делится на 3 шага.
Шаг 1: По имени класса перейти к глобальному списку классов, чтобы узнать, существует ли класс, если он существует, получить переменную класса хранения
Шаг 2: Определение является общим классом (не абстрактным классом или интерфейсом); если это обычный класс, контейнер ZVAL хранится для объекта, который вы хотите создать, и установите тип контейнера is_Object.
Шаг 3: Выполните операцию инициализации объекта и добавьте объект в глобальный список объектов (пул объектов)
Прикрепите структуру данных объекта:
typedef struct _zend_object {
zend_class_entry *ce; //对象的类结构
HashTable *properties; //对象属性
HashTable *guards; /* protects from __get/__set ... recursion */
} zend_object;
Получить и установить переменные-члены
Получить переменные-члены:
Первый шаг — получить свойства объекта, и проверить, есть ли свойство, соответствующее названию из свойств объекта, если есть — вернуть результат, если нет — перейти ко второму шагу.
Второй шаг, если есть магический метод get, вызовите этот метод, чтобы получить переменную, если нет, сообщите об ошибке
Установите переменные-члены:
Первый шаг - получить свойства объекта и проверить, есть ли свойство, соответствующее имени из свойств объекта.Если оно существует и существующее значение совпадает с устанавливаемым значением, ничего не делать, в противном случае выполните операцию присвоения переменной, если она не существует, перейдите к шагу 2
Второй шаг, если есть магический метод _set вызываем этот метод для установки переменной, если нет переходим к третьему шагу
На третьем шаге, если переменная-член не была установлена, добавьте переменную непосредственно в HashTable, где находится поле свойств объекта.
Суммировать
До сих пор мы почти говорили об основных принципах php. Конечно, в этот период многие студенты говорили мне, что они постепенно начали использовать php7.То, что вы сейчас объясняете, это все еще php5, не устареет ли он? На самом деле, мое объяснение php5 также для подготовки к php7.В конце концов, php7 является расширением php5.После понимания php5 будет легче понять php7. Более того, php постепенно совершенствовался со времен php5, поэтому нам необходимо разобраться в содержании php5. Но со следующей недели мы начнем сравнивать разницу между php7 и php5 снизу, так что следите за обновлениями~