вопрос по ООП

zerkms

TDD infected
Команда форума
grigori
Что значит "отложенное"?
вы так много кричали RTFM. ну чтож - тоже извольте почитать мануал, погуглить.

Вы знакомы с файловой системой Unix? При записи в файл по ссылке тоже должно происходить "отложенное копирование"?
при чём здесь фс униксов?

при чём здесь копипаст мануала и выделение того что ссылки не являются указателями?
Должно по каким правилам? Или Вы лично ожидаете этого по аналогии с практикой на _других_ языках?
я это ожидаю исходя из здравого смысла
Если с точки зрения работы скрипта - то $a['a'] и $ref становятся идентичными и ведут себя как ссылки (что и видно из примера).
угу, $a['a'] и $ref являются ссылками. однако почему $b, которое не является ссылкой, модифицирует значение $a['a'] ?

PHP:
$a = 1;
$ref =& $a;

$b = $a;

$b = 2;

var_dump($a);
что должен вывести этот код согласно вашим рассуждениям?
 

Vladson

Сильнобухер
Имхо исходя из здравого смысла (по крайней мере как я его вижу) $a должен оставаться массивом, $b должен быть копией его содержимого, а $ref ссылкой на $a.
(не знаю как на других языках, в бейсике например этого вообще нету)

Однако на практике после того как $ref становится ссылкой $a так-же становится ссылкой, а $b становится тем же чем и $a (т.е ссылкой) что ИМХО не правильно так как никто не просил менять тип $a на него просто сослались...
 

hermit_refined

Отшельник
Автор оригинала: grigori
PHP:
$a =array('a'=>1);
$ref=&$a['a'];

$b=$a;
$b['a']=2;

echo $a['a'];
AAAAпокалипсис! Всё, прямой доступ к элементам массива признается deprecated по мнению большого брата (aka умные дяди).
я написал пример как раз на основе аналогичного поведения массивов, вы обратили.
ну и? разве не апокалипсис? неужели вы думаете, что если по-моему мнению публичные свойства класса - зло, я благоволю к массивам?
да, они замечательно могут использоваться внутри классов, даже могут передаваться между объектами в качестве совокупности данных - только неизменяемой, ибо если с этими данными связанно хоть какое-то поведение, мы обязаны их инкапсулировать в объект.
в иных случаях, массивы - черные ящики. мы не знаем, что в них есть и чего в них нет. их использование на глобальном уровне - в большом проекте грозит сумасшествием для разработчиков. даже безо всяких ссылок.

(кстати, есть такая забавная деталь - суперглобальные массивы, которые при register_globals = off состоят из нормальных переменных, при register_globals = on - становятся состоящими из ссылок. в свое время я убил полдня на отладку в одном - признаться, не ахти написанном приложении - чтобы понять, почему все работает не так, как expected.)
PHP:
class X{
    private $x;
    function setX(&$x){
        $this->x=&$x;
    }
}
class Test
{
     protected $member = 0;
     function shout(){
         echo $this->member;
     }
     function work(){
         $this->member=2;
     }
     function __construct(X $x){
         $x->setX($this->member);
     }
}
вы бредите, не понимая к тому же смысла моего примера.
во-первых, в моем примере разработчик класса Test ни в чем не виноват (кроме того, что оставил публичные свойства), тем не менее непредсказуемое поведение наблюдается именно при работе с объектами этого класса. в вашем - (оставляя за скобками некорректность такой работы с объектами, как в вашем конструкторе класса Test) - разработчик видел интерфейс класса X, и если он передал защищенное свойство по ссылке другому объекту - он профнепригоден.
во-вторых, в вашем примере баг инкапсулирован в классе Test - достаточно заглянуть в конструктор и посмотреть на интерфейс класса X, чтобы понять, в чем дело (да-да, ошибки в ООП объектно-ориентированные и инкапсулированные). а куда разработчику в моем примере податься?..

All
странно, что мой пример с объектами никого не смутил, а с массивами - вызвал панику :))
по ссылке Преведа всё очень хорошо и правильно расписано. В мануале (искал полтора года назад) вразумительных объяснений нет, только в комментариях пользователей и на bugs.php.net с классической благодарностью за интерес к php :))
такое устройство ссылок, на мой взгляд, является совершенно дурацким, но если смотреть исходники, понятно, почему так было сделано.
слава богу, в php 5 нет никакой необходимости использовать ссылки вовсе (кроме некоторых оптимизаций внутри классов или отдельных методов, где это поведение вполне контролируется).
 

Bermuda

Новичок
Так я не понял, что же лучше?

Обращаться напрямую к публичным свойствам класса или использовать методы интерфейса для установки значений private свойств класса?
 

Vladson

Сильнобухер
Имхо публичные свойства класса для того и сделаны были чтоб к ним обращаться, но со стороны самой концепции ООП это не совсем "красиво"
 

Shturm

Гигант мысли
Автор оригинала: Bermuda
Так я не понял, что же лучше?...
Если использовать методы - появляется возможность информировать объект о том, что его свойство кем-то использовано.
Если не использовать - такой возможности нет.
Все это - вопрос практической необходимости.
 

Bermuda

Новичок
Ок, рассмотрим пример из жизни.

Класс: коты
Свойство: цвет = серый
Задача -- покрасить кота в зеленый цвет.

Вариант 1.
//Беру кота и крашу его в зеленый цвет
$коты->цвет = зелёный;

Вариант 2.
//Беру кота и прошу его поркасить самого себя в зеленый цвет
$коты->покрасьСебя(зелёный);

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

-~{}~ 12.01.07 13:30:

Автор оригинала: Shturm
Если использовать методы - появляется возможность информировать объект о том, что его свойство кем-то использовано.
Да, это несомненно плюс.
 

whirlwind

TDD infected, paranoid
Во-первых, попробуйте сделать

PHP:
interface TheCat {
   public $color = null;
}
получите ошибку. Это означает, что вы не можете гарантировать наличие публичных атрибутов в реализации класса. Вы можете гарантировать только наличие методов.
Допустим в системе есть
PHP:
class CatColourer {
     public function colour(TheCat $cat,$newColor){

     }
}
Так же у нас имеются две реализации кота. Одну из них написал Вася Пупкин, а другую - Петя Васечкин. При этом они между собой абсолютно не знакомы и стили кодирования у них разные: Вася использует атрибут currentColor, а Петя - Color.

Реализация colour не может знать, какой конкретно атрибут следует использовать для задания нового цвета. А вот если бы в интерфейсе TheCat был декларирован setColor/getColor то в реализации метода colour никаких проблем бы не возникало.

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

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

nerezus

Вселенский отказник
zerkms
пардон, не обратил внимание, что это не объкект )
извиняюсь :)
 

ONK

Пассивист PHPСluba
Выскажу своё мнение, по поводу кода демонстрирующего "странное" поведение ссылок.
Когда я делаю операцию копирования (= для простых типов и clone для объектов), я ожидаю получить сущность представляющую собой точную копию объекта на момент копирования (за исключением ресурсов, которые конечно всегда передаются по ссылке).
Я считаю, что приведённый код демонстрирует баг, связанный с текущим алгоритмом работы ZE со ссылками.
С моей точки зрения, даже если баг (багоподобное поведение) описано в документации, бегом оно не перестаёт быть.
 

Vladson

Сильнобухер
ONK
Полностью согласен (о чём уже сказал выше) операция копирования должна быть копированием а не чем-то ещё...
 

С.

Продвинутый новичок
Автор оригинала: Vladson
Имхо публичные свойства класса для того и сделаны были чтоб к ним обращаться, но со стороны самой концепции ООП это не совсем "красиво"
Это на каком соборе Церкви ООП такой догмат о некрасивости ввели? Я что-то пропустил?

Здесь так и не предложили ни одной причины, почему НАДО обращатся через методы, кроме того, что потом де переделывать легче. Чисто кодеровский подход: не как лучше работать будет, а как переделывать...

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

Тем более, что "со стороны самой концепции ООП" (C) Vladson) переделка одного класса не должно быть такой уж и большой проблемой. Изменение его поведение не должно коренным образом рушить всю структуру проекта. Если это у вас происходит, то значит вы оборачиваете GLOBALS в объекты и выдаете это за ООП.
 

ONK

Пассивист PHPСluba
С., вам уже множество примеров привели, почему внутреннюю начинку объекта стоит скрывать за интерфейсом методов. Если вы ещё не видите причин, по которым в большинстве случаев стоит избегать обращения к свойствам объекта напрямую, то возможно вам стоит переквалифицироваться в дворника, т.к. как вам нехватает способности к обучению.
Судя по вашим ответам у вас просто нет опыта написания хоть чуть чуть ОО приложений.
Класс может быть спроектирован верно "на момент его проектирования", но время и обстоятельства изменяют требования к его функциональности. Практика показывает что удобство/простота/скорость внедрения новой функциональности при полностью инкапсулированной внутренней структуре объекта на порядок выше, чем в случае, когда в коде приложения напрямую залезают в потроха объекта и тем самым связывают/фиксируют его внутреннюю структуру. При правильном подходе, фактически процесс добавления новых функциональностей сводится к редактированию кода самого объекта, и добавлению новых вариантов использования в прикладном коде. Не надо забывать, что сложность внутренней структуры одного объекта может быть на порядок выше, чем сложность всего прикладного кода, в котором он используется.

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

denver

?>Скриптер
Согласен с С.:
Есло класс изначально спроектирован верно (чего кодер сделать очевидно не может), то ничего переделывать не надо будет. Если вдруг обнаруживается, что в проекте класса недочет, то не заплаты надо лепить на него, а брать и кропотливо приводить его в соответствие. Да, лазить по программе. Да, менять код.
Допустим, система работает с классом Microscope, но вдруг выясняется что этот класс должен работать как Hummer. Есть два варианта решения:

1. Осознать изменение требований или ошибки первоначального проектирования, и перепроектировать ВСЮ систему (долго, дорого, качественно).
2. Осознать изменение требований или ошибки первоначального проектирования, и переписать _реализацию_ класса Microscope так, чтобы вел себя как Hummer, но только чтобы всю систему не трогать (быстро, дешево, после нас хоть потоп).

В целом:
- да, изменять класс (хоть и кардинально) состоящий ТОЛЬКО из методов, не меняя интерфейс, проще.
- менять-то проще, но стройность класса (и в целом фундамент системы) от этого размывается, так что (стратегически) бывает лучше перепроектировать систему.

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

Фанат

oncle terrible
Команда форума
перенес в теорию. полезный топик. не без лишнего, но в общем и целом - пример топика, каких хотелось бы побольше на форуме.
 

ONK

Пассивист PHPСluba
denver, Так не бывает, тоесть наверное бывает, но я не имею литературных слов, чтобы полностью выразить своё мнение о таком подходе к проектированию приложения.

Если рассматривать нормальный процесс проектирования / разработки приложения, идущий от общего к частному, то в случае с микроскопом, он всегда будет оставаться микроскопом. Просто в определённый момент времени разработчики проекта могут придти к решению, что для решения их задач нужен не оптический микроскоп, а электронный. И что мы имеем? микроскоп должен поддерживать теже операции юстировки иследуемого объекта, фокусировки и получения кадра изображения, только в отличии от оптического микроскопа внутри него вместо линз будет вакуумная колба со сканирующим электронным пучком. Надеюсь на этом примере понятно, почему не стоит залезать внутрь специализированного объекта?
 

grigori

( ͡° ͜ʖ ͡°)
Команда форума
Ура! Новый, самый модный Holy WAR продолжается! :)

Поддерживаю C и denver.

whirlwind,
попробуйте сделать interface
Товарисч из Харькова :) не понимает ... как отсутсвие поддержки публичных свойств у интерфейсов доказывает нецелесообразность использования полей.
Напиши
PHP:
abstract class A{
    public $x=2;
    abstract function abc();
}
и требуй, где надо, дочек класса А ...
Или тебе так уж часто нужна реализация множественных интерфейсов?

zerkms,
с какой стати ссылка?
в PHP любое копирование - ссылка.

ONK,
приведённый код демонстрирует баг, связанный с текущим алгоритмом работы ZE со ссылками
Он демонстрирует текущий алгоритм работы. Баг это или нет ... а давайте голосование сделаем? :)
Я за то, что это фича!

-~{}~ 13.01.07 18:37:

Автор оригинала: ONK
микроскоп должен поддерживать теже операции ...
только в отличии от оптического микроскопа внутри него вместо линз будет вакуумная колба...
Надеюсь на этом примере понятно, почему не стоит залезать внутрь специализированного объекта?
Не понятно, блин ... но я из Харькова, мне можно :)
У меня есть class User, у него есть поле user_id ... почему я не могу сделать его полем, а должен делать метод getUserId ?
Много лет писал
PHP:
class XXX{
isRegistered(){
    return ($this->user_id>0);
}
...
в коде:
if ($UserData->isRegistered()) ...
Пол-года назад плюнул, теперь пишу
if ($UserData->user_id)

В рамках текущей сессии user_id - константа... новый пользователь - новый объект.
Нафига мне эти навороты с методами?

Так же с first_name, last_name, email ...

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