Сколько экземпляров объекта создастся в памяти при интерпретации в php следующей строки кода

Обновлено: 06.07.2024

При создании программы на PHP и отдельных ее блоков нам вполне может хватить той функциональности, которую представляют функции. Однако PHP имеет и другие возможности по созданию программ, которые представляет объектно-ориентированное программирование. В ряде случаев программы, использующие ООП, проще в понимании, их легче поддерживать и изменять.

Ключевыми понятиями парадигмы ООП являются понятия "класс" и "объект". Описанием объекта является класс, а объект представляет экземпляр этого класса. Можно провести следующую аналогию: например, у каждого человека есть имя, определенный возраст, вес, какие-то другие параметры. То есть некоторый шаблон, который содержит набор параметров человека - этот шаблон можно назвать классом. А реально же существующий человек с конкретным именем, возрастом, весом и т.д. является объектом или экземпляром этого класса.

Для создания класса в PHP используется ключевое слово class , после которого идет название класса и фигурные скобки <> - блок кода класса. Например, новый класс, представляющий пользователя:

Чтобы создать объект класса Person, применяется ключевое слово new :

В данном случае переменная $person является объектом класса Person . С помощью функции print_r() можно вывести содержимое объекта, как и в случае с массивами.

При этом неважно, определяется класс до или после создания объекта. Например, мы можем сначала определить переменную класса, а потом определить этот класс:

Свойства и методы

Класс может содержать переменные, которые описывают какие-то признаки объекта, его состояние и которые еще назывют свойствами или атрибутам. И также класс класс может содержать функции, которые еще назвают методами и которые определяют его поведение.

Так, добавим в класс Person несколько свойств и методов:

Здесь класс Person содержит два свойства: $name и $age . Свойства объявляются как обычные переменные, перед которыми стоит модификатор доступа - в данном случае модификатор public .

Методы представляют обычные функции, которые выполняют определенные действия. Здесь функция hello() просто выводит приветствие.

После создания объекта класса Person:

Мы можем через имя переменной класса обращаться к его свойствам и методам. Чтобы обратиться к свойствам и методам объекта применяется оператор доступа -> . Например, установить значения свойств:

Или получить значение (например, присвоить его переменной):

Или вызвать методы объекта:

В итоге мы получим следующий вывод браузера:

При этом свойствам можно задать в классе некоторые начальные значения:

Ключевое слово this

Для обращения к свойствам и методам объекта внутри его класса применяется ключевое слово this . Например, определим в классе метод для вывода информации об объекте:

Для обращения к полям и методам внутри класса также применяется оператор доступа -> , перед которым идет $this . Причем это $this указывает именно на текущий объект. Что это значит в практическом плане? Например:

$this фактически будет указывать на переменную $tom . Тогда как при вызове

$this будет указывать на переменную $bob .

Сравнение объектов

При сравнении объектов классов следует принимать во внимание ряд особенностей. В частности, при использовании оператора равенства == два объекта считаются равными, если они представляют один и тот же класс и их свойства имеют одинаковые значения.

А при использовании оператора эквивалентности === оба объекта считаются равными, если обе переменных классах указывают на один и тот же экземпляр класса.

Рассмотрим на примере:

Здесь сравниваются две переменных - $tom и $tomas. Они представляют один и тот же класс Person, и их свойства имеют одни и те же значения. Однако они представляют разные объекты. Поэтому при сравнении оператор == возвратит true , а оператор === - false :

Возьмем другой пример, когда обе переменных представляют один и тот же объект:

Здесь объект класса Person создается только один раз: $person = new Person(); . И затем обе переменных $tom и $tomas будут указывать на этот объект. При этом не имеет значения, для какой именно переменной мы устанавливаем свойства. Так как в реальности это будет один и тот же объект. В итоге и оператор == , и оператор === при сравнении возвратят true

В PHP, если вы создаете массив объектов, копируются ли методы объекта (не члены данных) для каждого экземпляра объекта в массиве или только один раз? Я бы предположил, что по причинам памяти, последнее верно; Я просто хотел подтвердить сообществу StackOverflow, что это правда.

Например, предположим, что у меня есть класс MyClass с парой методов, т.е.

Очевидно, что на самом деле method1 () и method2 () не являются пустыми функциями. Теперь предположим, что я создаю массив из этих объектов:

Таким образом, PHP хранит в памяти три набора элементов данных для каждого из трех экземпляров объекта. Мой вопрос: хранит ли PHP также копии методов method1 () и method2 () (и конструктора) 3 раза для каждого из трех элементов $ arr? Я пытаюсь решить, не будет ли массив из

3 объектов слишком интенсивным для памяти из-за необходимости хранить в памяти 200 копий каждого метода.

Спасибо за ваше время.

Конечно, метод по определению ссылка к процедуре? В этом случае механизм процедуры будет определен только один раз (когда вы загружаете класс, не когда вы создаете экземпляр объекта), и все экземпляры будут просто указывать на эту процедуру. Это чистое предположение, но я не вижу другого пути для любого типа метода / функции, если только это не закрытие. - DaveRandom

Хм. хороший вопрос. Интересно, что случится с любыми статическими переменными, определенными внутри этих методов. Будет ли это одна статическая переменная, совместно используемая каждым экземпляром метода, или каждый экземпляр получит свою собственную уникальную статическую переменную. - Marc B

@DaveRandom В Javascript, когда вы определяете класс, методы встраиваются в объект. Их содержимое не «разделяется» между экземплярами. - Matthieu Napoli

@Matthieu Согласен, но Javascript - это совершенно другая игра с мячом, так как более или менее все в JS - это сам по себе объект, включая метод. Но в равной степени это зависит от того, как вы определяете метод - если вы это делаете String.prototype.methodName = function () <>; у каждого строкового объекта есть метод, называемый methodName но не у всех есть собственная копия процедуры, они будут вызывать метод, принадлежащий String.prototype . Пока ты не сделаешь mystr.methodName = function () <>; и переопределите этот метод, затем mystr есть собственная копия. Но для PHP (я считаю) мое утверждение верно. - DaveRandom

2 ответы

По определению (а это надежная code) функция существует только один раз. Вот почему вы создаете код (а не данные).

Однако затем вы можете использовать свой код для получения большого количества данных. Но это уже другая история;).

Поэтому, если вы не дублируете код для объектов без необходимости, ваши функции будут существовать только один раз. Независимо от того, сколько случаев кода, который вы создаете. Дублируются только данные, связанные с кодом (члены класса).

Дает вам строгую ошибку стандартов. Вы не можете назначить ссылку / псевдоним с new ключевое слово. Вероятно, на этот способ написания повлиял код PHP 4, но это изменилось с PHP 5, который представил хранилище объектов.

ответ дан 20 окт '11, 02:10


«По определению функция существует только один раз»> Нет, например, в Javascript это не так, см. Мой ответ. Однако это верно для PHP. - Матье Наполи

Что ж, тогда вы должны прочитать мой комментарий . Я сказал "например". Просто вы говорите неправильное утверждение, функция не всегда существует однажды. Я думаю, что ОП задал интересный вопрос, учитывая, что это не всегда один и тот же ответ в зависимости от языка, поэтому стоит быть «придирчивым» и точным. (и гнев, если хотите, это очень важно) - Матье Наполи

Спасибо за предупреждение о строгой ошибке стандартов. Я новичок в программировании на PHP5 и ценю совет. - user1004061

Содержимое метода будет сохранено в памяти только один раз. Каждый объект PHP (указанного класса) будет иметь ссылку на метод.

Итак, в заключение: вам не нужно заботиться о размере памяти ваших методов, если вы планируете иметь много объектов. Просто позаботьтесь о размере памяти атрибутов объектов.

Объекты в PHP — это просто ещё один тип данных. Объект позволяет хранить в переменной набор из свойств и их значений, а также встроенные функции. Это делает объекты похожими по своей структуре на ассоциативные массивы. Но отличие от массивов всё-таки есть, и при этом достаточно важное — объекты могут иметь внутреннее состояние.

Особенности объектов и их отличия от массивов

Давайте разберёмся, что такое PHP-объект. Как сказано выше, объекты похожи на массивы, но со своими особенностями. Объекты могут содержать отдельные значения, каждое под своим ключом. Эти значения называются свойствами объекта.
Также объекты могут иметь внутри себя функции — их называют методами объекта. Методы могут обращаться к любым свойствам объекта, читать и записывать туда данные.

Значение свойства объекта может быть любого типа: число, строка, массив, другой объект. Но, в отличие от массива, объекты не позволяют добавлять в себя новые значения. То есть объект всегда имеет конечное число своих свойств и методов. Менять значения существующих свойств можно, а удалять и заменять их — нельзя. Что в корне отличается от поведения массива, ведь там добавлять и удалять значения можно в любое время.

Но самая большая особенность объектов — это то, как они создаются. Если массив создается либо пустым, либо сразу с набором значений, то объекты устроены иначе. Дело в том, что объекты не существуют сами по себе. Чтобы создать новый объект, вам придётся вначале создать его описание — класс.
Класс — это как бы чертёж объекта. Класс описывает то, из чего состоит объект. Мы разберёмся с классами чуть позже.

Анатомия объекта

Как же устроен объект изнутри? Его содержимое можно поделить на две группы: свойства и методы.
Свойства могут быть двух видов: публичные и скрытые. К публичным свойствам можно обращаться за пределами объекта, точно так же, как вы обращаетесь к элементам массива по его ключам.
Скрытые свойства не имеют аналогов в массиве. Они доступны для чтения и изменения только внутри самого объекта — и это могут делать его методы.

Вторая группа — это методы объекта.
Набор методов также называется поведением объекта. Как и свойства, методы бывают публичными и скрытыми. Публичные методы объекта можно вызывать из внешнего кода, а скрытые только из самого объекта. Методы способны обращаться к свойствам объекта также просто, как если бы это были их внутренние переменные или аргументы.

Классы

Класс — это шаблон, по которому создаются объекты.

Напомню, что классы — это описания объектов. Мы не можем создать объект «на лету», как это происходит с массивами. Объект может быть создан только на основе своего описания — класса. Этим, кстати, реализация объектов в PHP отличается от JavaScript. В JS объектам не нужны никакие классы, и они могут быть созданы и модифицированы когда угодно и как угодно.

Класс как чертёж

Зачем же нужны классы, и почему объекты не могут существовать без них?

Здесь аналогия очень простая: класс – это чертёж, максимально подробное описание того, как должно выглядеть изделие. Сам по себе класс не является чем-то физическим и осязаемым, то есть мы не можем использовать его в коде непосредственно. Вместо этого класс является схемой, структурой, на основе которой будет создан объект.

Жизненный цикл объекта

Любая работа с объектами в PHP состоит из следующих этапов.
Начинается всё с создания класса. В классе мы фиксируем из каких свойств и методов будет состоять каждый его экземпляр. Также в классе можно задать начальные значения для каждого свойства.
Имея класс, возможно создать его экземпляр — объект.

Классы в PHP принято сохранять в отдельных файлах, поэтому вначале вы подключаете этот сценарий там, где он необходим. Затем вызываете процедуру создания нового объекта на основе этого класса.

Чтобы использовать объект в дальнейшем, его следует, как всегда, назначить переменной. Затем вы будете работать с объектом через переменную: вызывать методы и обращаться к свойствам.

Пример создания объекта на основе класса

Создание объекта на основе класса:

Разбор примера

Разберёмся с тем, что здесь происходит.
Начнём с целей создания данного класса. Его задача — хранить в объекте данные о погоде за конкретный день, а также предоставлять сводку за этот день в текстовом виде.

В классе определено четыре скрытых свойства. Это значит, что к ним не будет доступа за пределами объекта. Читать и записывать эти свойства могут только внутренние методы объекта. Сами свойства хранят температурные параметры (температуру, осадки), дату и дополнительный комментарий к записи. Некоторым свойствам задано значение по умолчанию.

Далее идёт перечисление методов. И начинается всё с метода, у которого особое имя и значение — __construct .

Что такое конструктор объекта

Методы объекта вызываются из внешнего кода, при явном обращении к ним с указанием имени. Но если назвать один метод __construct то он будет вызываться автоматически в момент создания объекта на основе класса.

Конструкторы объектов используются для инициализации каких-либо значений и выполнении других подготовительных операций. В нашем примере конструктор устанавливает содержимое скрытых свойств.

Обращение к свойствам и методам объекта

Посмотрим, как внутри метода происходит обращение к его свойствам.
Во-первых, для этого используется специальная переменная this, которая всегда присутствует внутри объекта и ссылается на него самого.

Во-вторых, для обращения к методам и свойствам объекта нужен специальный синтаксис: «стрелочка». Такая стрелочка отделяет имя свойства или метода от имени объекта. Это аналог квадратных скобок при работе с массивами.

Метод с именем isCold() нужен, чтобы узнать было ли холодно в тот день, основываясь на показаниях температуры в градусах.
Метод setRainStatus() устанавливает логическое значение, которое показывает статус осадков в день наблюдения.
Метод getDayDescription() формирует текстовое описание погоды на заданную дату.

Создание объекта на основе класса

Написав класс, мы выполнили большую часть работы. Теперь нам предстоит создать новый объект на основе этого класса и показать, как с ним работать.
Новый объект создается с помощью ключевого слова new, после которого идёт имя его класса. В круглых скобках надо передать все аргументы в метод __construct , если он был написан. Класс не обязан содержать этот метод, и если его нет, то круглые скобки не обязательны.

В коде мы передаём в конструктор почти все параметры погодных наблюдений. Затем для созданного объекта вызываются его методы: первый устанавливает значения осадков, а второй возвращает текстовое описание погоды.

Существует способ получить общую память, используемую PHP ( memory_get_usage() ), но как получить размер в памяти отдельного объекта?

Я, очевидно, не говорю о count() , так как я хочу количество байтов в потенциально сложной структуре данных.

спросил(а) 2021-01-25T21:17:23+03:00 9 месяцев, 4 недели назад

Вы можете вызвать memory_get_usage() до и после выделения вашего класса, как показано в в этом примере из IBM. Вы даже можете создать оболочку для этого, возможно, сохраняя результат в переменной-члене самого сложного класса.

Чтобы прояснить часть хранения выделенного объема памяти, вы можете сделать что-то вроде этого:

В любой момент в будущем вы можете проверить allocizeize, чтобы увидеть, насколько большой этот объект был во время выделения. Если вы добавите к нему после выделения, тем не менее, allocSize больше не будет точным.

ответил(а) 2021-01-25T21:17:23+03:00 9 месяцев, 4 недели назад

Не имеет смысла пытаться сериализовать объект и читать длину строки? Очевидно, что это будет несколько байтов, потому что сериализованная строка имеет s: 'string', поэтому s: '' является дополнительными байтами. если serialize не может быть таким же, как PHP хранит объекты.

Другая беспорядочная, но, возможно, точная мысль:

Предполагая переменную экземпляра класса, которая была обработана несколько раз с момента создания экземпляра:

$mem может быть точным объемом памяти, выделенной для $DB;

ответил(а) 2021-01-25T21:17:23+03:00 9 месяцев, 4 недели назад

Я не думаю, что это вполне возможно; Я никогда не видел ничего, что позволило бы вам получить размер объекта в памяти.

Решение для получения довольно грубой идеи может быть связано с сериализацией ваших данных и использованием strlen на этом. Но это действительно будет чем-то вроде оценки. Я бы не совсем полагался на что-либо подобное, фактически.

Даже debug_zval_dump не делает этого: он выводит данные в переменной и refcount, но не использует память:

Читайте также: