Когда использовать статичный по сравнению с инстанцированными классами

Чередование if и for в пониманиях списка

>>> [(x, y) for x in range(4) if x % 2 == 1 for y in range(4)]
[(1, 0), (1, 1), (1, 2), (1, 3), (3, 0), (3, 1), (3, 2), (3, 3)]

я никогда не понимал это, пока я не изучил Haskell.

168
задан user73119 26 July 2009 в 21:30
поделиться

7 ответов

Джонатан,

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

(A) Вы не владеете своим сервером. Вы не можете вносить общесистемные изменения в конфигурацию вашего сервера.

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

(C) Ваш веб-сервер - Apache или Microsoft IIS.

.

«Изменение файла» дает некоторые возможности :

(1) При посещении URL-адреса отображается исходное содержимое файла и кнопка «Изменить». Если вы нажмете кнопку «Изменить», исходное содержимое будет показано в текстовой области и появится кнопка «Сохранить». После завершения редактирования нажмите «Сохранить», чтобы сохранить изменения.

(2) НЕТ интерфейса редактирования. Интерфейс похож на "файловый менеджер". Вы просто загружаете другой файл с тем же именем, чтобы перезаписать / заменить исходный файл.

.

Если вы хотите (1) выше, вы должны написать серверный сценарий ( например, PHP, ASP и т. д.) (Конечно, вы также можете использовать серверные скрипты, написанные другими людьми!). Убедитесь, что ваш сервер поддерживает выбранный вами язык (+ зависимые библиотеки).

Если вы хотите (2) выше, есть много способов добиться этого, но я боюсь, что необходимо изменить конфигурацию сервера:

(1) Вы можете добавить сервер FTP к своему серверу (если можете). Затем, используя Firefox с плагином FireFTP (или используя Internet Explorer, если это ваш выбор), вы можете загрузить / загрузить файл.

(2) Вы можете добавить / включить модуль WebDAV в свой веб сервер. Добавление «WebDAV» Функция позволяет открывать / выгружать файлы через HTTP. Microsoft называет это «веб-папкой». Linux и Apple называют это «WebDAV» (первоначальное название). Не должно возникнуть проблем с загрузкой файлов с помощью Windows Explorer (Windows) / nautilus (Linux - Gnome) / Finder (Max OS X), даже если они не являются браузерами.

.

Пожалуйста, предоставьте дополнительную информацию для ваш вопрос.

Кэндзи

везде - Говоря о пользователе, у вас может быть только один пользователь - что не так уж и хорошо, не так ли?

Что я могу сказать для системы блогов? На самом деле, я не так много написал бы статичным; может быть, класс доступа к БД, но, вероятно, нет, в конце концов ^^

122
ответ дан 23 November 2019 в 20:56
поделиться

Таким образом, в PHP статика может применяться к функциям или переменным. Нестатические переменные привязаны к конкретному экземпляру класса. Нестатические методы действуют на экземпляр класса. Итак, давайте создадим класс под названием BlogPost .

title будет нестатическим членом. Он содержит заголовок этого сообщения в блоге. У нас также может быть метод под названием find_related () . Он не статичен, поскольку требует информации из определенного экземпляра класса сообщения в блоге.

Этот класс будет выглядеть примерно так:

class blog_post {
    public $title;
    public $my_dao;

    public function find_related() {
        $this->my_dao->find_all_with_title_words($this->title);
    }
}

С другой стороны, используя статические функции, вы можете написать такой класс:

class blog_post_helper {
    public static function find_related($blog_post) {
         // Do stuff.
    }
}

В этом случае, поскольку функция является статической и не действует ни на одно конкретное сообщение в блоге, вы должны передать сообщение в блоге в качестве аргумента.

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


Обновление: я бы также добавил, что решение редко бывает между методами экземпляра и статическими методами, и больше между использованием классов и использованием ассоциативных массивов. Например, в приложении для ведения блога вы либо читаете сообщения блога из базы данных и конвертируете их в объекты, либо оставляете их в наборе результатов и обрабатываете как ассоциативные массивы. Затем вы пишете функции, которые принимают в качестве аргументов ассоциативные массивы или списки ассоциативных массивов.

В OO-сценарии вы пишете методы в своем классе BlogPost , которые воздействуют на отдельные сообщения, и вы пишете статические методы, которые работают с коллекциями сообщений.

22
ответ дан 23 November 2019 в 20:56
поделиться

Основные две причины против использования статических методов:

  • код, использующий статические методы, трудно протестировать
  • код, использующий статические методы, трудно расширить

Наличие статического вызова метода внутри какой-то другой метод на самом деле хуже, чем импорт глобальной переменной. В PHP классы являются глобальными символами, поэтому каждый раз, когда вы вызываете статический метод, вы полагаетесь на глобальный символ (имя класса). Это тот случай, когда глобальность - это зло. У меня были проблемы с таким подходом к некоторым компонентам Zend Framework. Существуют классы, которые используют вызовы статических методов (фабрики) для создания объектов. Я не мог предоставить этому экземпляру другую фабрику, чтобы получить обратно настроенный объект. Решение этой проблемы состоит в том, чтобы использовать только экземпляры и методы instace и применять синглтоны и тому подобное в начале программы.

Мишко Хевери , который работает Agile Coach в Google, имеет интересную теорию, или скорее советую, что мы должны отделить время создания объекта от времени использования объекта. Таким образом, жизненный цикл программы делится на две части. Первая часть (скажем, метод main () ), которая заботится обо всех связях между объектами в вашем приложении и той части, которая выполняет фактическую работу.

Итак, вместо того, чтобы иметь:

class HttpClient
{
    public function request()
    {
        return HttpResponse::build();
    }
}

Нам лучше сделать:

class HttpClient
{
    private $httpResponseFactory;

    public function __construct($httpResponseFactory)
    {
        $this->httpResponseFactory = $httpResponseFactory;
    }

    public function request()
    {
        return $this->httpResponseFactory->build();
    }
}

А затем, на главной / индексной странице, мы сделаем (это этап связывания объектов или время для создания графа экземпляров, которые будут использоваться программой):

$httpResponseFactory = new HttpResponseFactory;
$httpClient          = new HttpClient($httpResponseFactory);
$httpResponse        = $httpClient->request();

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

Мишко Хевери также проводит четкое различие между синглетонами и синглетонами (с заглавной буквой S или без нее). Отличие очень простое. Синглтоны со строчными буквами "s" принудительно подключаются проводкой в ​​index / main. Вы создаете экземпляр объекта класса, который не реализует шаблон Singleton, и заботитесь о том, чтобы вы передавали этот экземпляр только любому другому экземпляру, который в нем нуждается. С другой стороны, Синглтон с большой буквы "S" это реализация классического (анти) паттерна. По сути, это замаскированный глобал, который не имеет особого смысла в мире PHP. Я не видел ни одного до этого момента. Если вы хотите, чтобы все ваши классы использовали одно соединение с БД, лучше сделать это следующим образом:

$db = new DbConnection;

$users    = new UserCollection($db);
$posts    = new PostCollection($db);
$comments = new CommentsCollection($db);

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

/**
 * An example of a test using PHPUnit. The point is to see how easy it is to
 * pass the UserCollection constructor an alternative implementation of
 * DbCollection.
 */
class UserCollection extends PHPUnit_Framework_TestCase
{
    public function testGetAllComments()
    {
        $mockedMethods = array('query');
        $dbMock = $this->getMock('DbConnection', $mockedMethods);
        $dbMock->expects($this->any())
               ->method('query')
               ->will($this->returnValue(array('John', 'George')));

        $userCollection = new UserCollection($dbMock);
        $allUsers       = $userCollection->getAll();

        $this->assertEquals(array('John', 'George'), $allUsers);
    }
}

Единственная ситуация, в которой я бы использовал (и я использовал их для имитации объекта прототипа JavaScript в PHP 5.3) статические члены - это когда я знаю, что соответствующее поле будет иметь одно и то же значение кросс-экземпляра. На этом этапе вы можете использовать статическое свойство и, возможно, пару статических методов получения / установки. В любом случае не забудьте добавить возможность переопределения статического члена членом экземпляра. Например, Zend Framework использовала статическое свойство, чтобы указать имя класса адаптера БД, используемого в экземплярах Zend_Db_Table . Прошло какое-то время с тех пор, как я их использовал, поэтому, возможно, это больше не актуально, но я так помню.

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

Например, Zend Framework использовала статическое свойство, чтобы указать имя класса адаптера БД, используемого в экземплярах Zend_Db_Table . Прошло некоторое время с тех пор, как я их использовал, поэтому, возможно, это больше не актуально, но я так помню.

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

Например, Zend Framework использовала статическое свойство, чтобы указать имя класса адаптера БД, используемого в экземплярах Zend_Db_Table . Прошло какое-то время с тех пор, как я их использовал, поэтому, возможно, это больше не актуально, но я так помню.

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

69
ответ дан 23 November 2019 в 20:56
поделиться

Это все просто стиль?

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

14
ответ дан 23 November 2019 в 20:56
поделиться

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

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

  • дать им всем пространство имен - избегая любых конфликтов имен
  • , держите их физически вместе, вместо того, чтобы рассредоточиться по проекту - другим разработчикам будет легче найти то, что ' уже доступны и с меньшей вероятностью изобретут колесо
  • , позвольте мне использовать константы класса вместо глобальных определений для любых магических значений

, это просто в целом удобный способ обеспечить более высокую сплоченность и более низкую связь.

И FWIW - по крайней мере в PHP5 нет такого понятия, как "статические классы"; методы и свойства могут быть статическими. Чтобы предотвратить создание экземпляра класса, его также можно объявить абстрактным.

10
ответ дан 23 November 2019 в 20:56
поделиться

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

3
ответ дан 23 November 2019 в 20:56
поделиться

Сначала спросите себя, что будет представлять этот объект? Экземпляр объекта хорош для работы с отдельными наборами динамических данных.

Хорошим примером может служить ORM или уровень абстракции базы данных. У вас может быть несколько подключений к базе данных.

$db1 = new Db(array('host' => $host1, 'username' => $username1, 'password' => $password1));
$db2 = new Db(array('host' => $host2, 'username' => $username2, 'password' => $password2));

Эти два подключения теперь могут работать независимо:

$someRecordsFromDb1 = $db1->getRows($selectStatement);
$someRecordsFromDb2 = $db2->getRows($selectStatement);

Теперь в этом пакете / библиотеке могут быть другие классы, такие как Db_Row и т. Д., Для представления определенной строки, возвращаемой оператором SELECT. Если бы этот класс Db_Row был статическим классом, это предполагало бы, что у вас есть только одна строка данных в одной базе данных, и было бы невозможно сделать то, что мог бы экземпляр объекта. С помощью экземпляра теперь вы можете иметь неограниченное количество строк в неограниченном количестве таблиц в неограниченном количестве баз данных. Единственное ограничение - это оборудование сервера;).

Например, если метод getRows объекта Db возвращает массив объектов Db_Row, теперь вы можете работать с каждой строкой независимо друг от друга:

foreach ($someRecordsFromDb1 as $row) {
    // change some values
    $row->someFieldValue = 'I am the value for someFieldValue';
    $row->anotherDbField = 1;

    // now save that record/row
    $row->save();
}

foreach ($someRecordsFromDb2 as $row) {
    // delete a row
    $row->delete();
}

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

В одной части вашего приложения:

Session::set('someVar', 'toThisValue');

И в другой части:

Session::get('someVar'); // returns 'toThisValue'

Поскольку в каждый сеанс одновременно может быть только один пользователь, существует нет смысла создавать экземпляр для сеанса.

Я надеюсь, что это поможет, наряду с другими ответами, которые помогут прояснить ситуацию. В качестве примечания обратите внимание на « сцепление » и « сцепление ». В них описаны некоторые очень, очень хорошие практики, которые можно использовать при написании кода, которые применимы ко всем языкам программирования.

теперь вы можете работать с каждой строкой независимо друг от друга:

foreach ($someRecordsFromDb1 as $row) {
    // change some values
    $row->someFieldValue = 'I am the value for someFieldValue';
    $row->anotherDbField = 1;

    // now save that record/row
    $row->save();
}

foreach ($someRecordsFromDb2 as $row) {
    // delete a row
    $row->delete();
}

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

В одна часть вашего приложения:

Session::set('someVar', 'toThisValue');

И в другой части:

Session::get('someVar'); // returns 'toThisValue'

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

Я надеюсь это помогает вместе с другими ответами прояснить ситуацию. В качестве примечания обратите внимание на « сцепление » и « сцепление ». В них описаны некоторые очень, очень хорошие практики, которые можно использовать при написании кода, которые применимы ко всем языкам программирования.

теперь вы можете работать с каждой строкой независимо друг от друга:

foreach ($someRecordsFromDb1 as $row) {
    // change some values
    $row->someFieldValue = 'I am the value for someFieldValue';
    $row->anotherDbField = 1;

    // now save that record/row
    $row->save();
}

foreach ($someRecordsFromDb2 as $row) {
    // delete a row
    $row->delete();
}

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

В одна часть вашего приложения:

Session::set('someVar', 'toThisValue');

И в другой части:

Session::get('someVar'); // returns 'toThisValue'

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

Я надеюсь это помогает вместе с другими ответами прояснить ситуацию. В качестве примечания обратите внимание на « сцепление » и « сцепление ». В них описаны некоторые очень, очень хорошие практики, которые можно использовать при написании кода, которые применимы ко всем языкам программирования.

foreach ($someRecordsFromDb1 as $row) {
    // change some values
    $row->someFieldValue = 'I am the value for someFieldValue';
    $row->anotherDbField = 1;

    // now save that record/row
    $row->save();
}

foreach ($someRecordsFromDb2 as $row) {
    // delete a row
    $row->delete();
}

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

В одной части вашего приложения:

Session::set('someVar', 'toThisValue');

И в другой part:

Session::get('someVar'); // returns 'toThisValue'

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

Я надеюсь, что это поможет вместе с другими ответами, которые помогут прояснить ситуацию. вверх. В качестве примечания обратите внимание на « сцепление » и « сцепление ». В них описаны некоторые очень, очень хорошие практики, которые можно использовать при написании кода, которые применимы ко всем языкам программирования.

foreach ($someRecordsFromDb1 as $row) {
    // change some values
    $row->someFieldValue = 'I am the value for someFieldValue';
    $row->anotherDbField = 1;

    // now save that record/row
    $row->save();
}

foreach ($someRecordsFromDb2 as $row) {
    // delete a row
    $row->delete();
}

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

В одной части вашего приложения:

Session::set('someVar', 'toThisValue');

И в другой part:

Session::get('someVar'); // returns 'toThisValue'

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

Я надеюсь, что это поможет вместе с другими ответами, которые помогут прояснить ситуацию вверх. В качестве примечания обратите внимание на « сцепление » и « сцепление ». В них описаны некоторые очень, очень хорошие практики, которые можно использовать при написании кода, которые применимы ко всем языкам программирования.

Session::get('someVar'); // returns 'toThisValue'

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

Я надеюсь, что это поможет вместе с другими ответами, которые помогут прояснить ситуацию. В качестве примечания обратите внимание на « сцепление » и « сцепление ». В них описаны некоторые очень, очень хорошие практики, которые можно использовать при написании кода, которые применимы ко всем языкам программирования.

Session::get('someVar'); // returns 'toThisValue'

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

Я надеюсь, что это поможет вместе с другими ответами, которые помогут прояснить ситуацию. В качестве примечания обратите внимание на « сцепление » и « сцепление ». В них описаны некоторые очень, очень хорошие практики, которые можно использовать при написании кода, которые применимы ко всем языкам программирования.

7
ответ дан 23 November 2019 в 20:56
поделиться
Другие вопросы по тегам:

Похожие вопросы: