<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>ebene7 &#187; Observer</title>
	<atom:link href="http://blog.ebene7.com/schlagwort/observer/feed/" rel="self" type="application/rss+xml" />
	<link>https://blog.ebene7.com</link>
	<description></description>
	<lastBuildDate>Tue, 04 Jun 2013 18:57:27 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.2.1</generator>
		<item>
		<title>Symfony2: Event-Listener über Annotations registrieren</title>
		<link>https://blog.ebene7.com/2012/02/27/symfony2-event-listener-ueber-annotations-registrieren/</link>
		<comments>https://blog.ebene7.com/2012/02/27/symfony2-event-listener-ueber-annotations-registrieren/#comments</comments>
		<pubDate>Mon, 27 Feb 2012 05:00:04 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Annotations]]></category>
		<category><![CDATA[Eventhandling]]></category>
		<category><![CDATA[Observer]]></category>
		<category><![CDATA[Reflection]]></category>
		<category><![CDATA[Symfony2]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=3449</guid>
		<description><![CDATA[In den letzten Monaten habe ich hier leider nicht sehr viel geschrieben und freue mich daher um so mehr, wenn ich dann mal wieder über ein spanndendes Thema schreiben kann. So dann auch, wie ich finde, heute. Es geht um &#8230; <a href="https://blog.ebene7.com/2012/02/27/symfony2-event-listener-ueber-annotations-registrieren/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>In den letzten Monaten habe ich hier leider nicht sehr viel geschrieben und freue mich daher um so mehr, wenn ich dann mal wieder über ein spanndendes Thema schreiben kann. So dann auch, wie ich finde, heute.</p>
<p>Es geht um zwei einfache, aber zugleich sehr nützliche Dinge, die das PHP-Framework Symfony2 mitbringt: Ein einfaches, flexibles Event-Handling und Annotations.<span id="more-3449"></span></p>
<p>Für mich waren die letzten drei Wochen auch die ersten Gehversuche mit Symfony2 und bislang wurden alle meine Erwartungen bestätigt. Das Framework ist sehr flexibel, aber auch recht komplex. Wer allerdings andere MVC-Frameworks wie Zend kennt, der wird sich auch hier schnell zurecht finden.</p>
<p>So, genug Lob an der Stelle. Neben der positiven Eigenschafft eines Eventhandlingsystems fiel mir auch gleich die Art auf, wie sich in Symfony2 Controllerrouten mit Annotations konfigurieren lassen.</p>
<p>Leider habe ich nichts Vergleichbares für Eventlistener gefunden und die klassische Konfiguration über YML gefiel mir dann auch nicht mehr so recht. Das nahm ich dann also gleich mal als praxisnahes Kennenlernbeispiel her und habe mir da was gebaut.</p>
<p>Als erstes braucht es immer einen Auslöser, damit die Annotations verarbeitet werden. Dafür habe ich mich an das Event &#8220;kernel.request&#8221; gehängt, das noch vor dem Kontrolleraufruf verarbeitet werden kann.</p>
<p>Einen speziellen Listener hatte ich erst dazwischen, habe es dann später aber wieder etwas vereinfacht. Mein Code entspricht vielleicht nicht allen Symfony-Richtlinien, aber zum Arbeiten und Erklären reicht es aus.</p>
<p>Zum Verarbeiten der Annotations habe ich eine einfache Klasse aufgebaut und mich dabei an den &#8220;Route()&#8221;-Annotations orientiert. Die Methode &#8220;findClass()&#8221; ist aus bestehendem Code &#8220;recycled&#8221;, da sie anders schwerer erreichbar wäre.</p>
<pre>&lt;?php
namespace MyNamespace\Annotations;

use Doctrine\Common\Annotations\Reader;
use Symfony\Component\EventDispatcher\EventDispatcher;

class AnnotatedEventClassLoader
{
  private $reader;
  private $eventDispatcher;
  private $eventAnnotationClass  = 'MyNamespace\\Annotations\\Event';

  /**
   * Constructor
   *
   * @param    Reader $reader
   * @param    EventDispatcher $eventDispatcher
   * @return    void
   */
  public function __construct(
    Reader $reader, EventDispatcher $eventDispatcher) {
    $this-&gt;reader = $reader;
    $this-&gt;eventDispatcher = $eventDispatcher;
  }

  public function init() {
    $listenersDir = realpath(__DIR__ . '/../../Listener');

    $iterator = new \RecursiveIteratorIterator(
      new \RecursiveDirectoryIterator($listenersDir),
        \RecursiveIteratorIterator::LEAVES_ONLY);

    foreach ($iterator as $file) {
      if (!$file-&gt;isFile() || '.php' !== substr($file-&gt;getFilename(), -4)) {
        continue;
      }

      if ($class = $this-&gt;findClass($file)) {
        $reflClass = new \ReflectionClass($class);
        if ($reflClass-&gt;isAbstract()) { continue; }

        foreach($reflClass-&gt;getMethods() as $method) {
          $annotation = $this-&gt;reader-&gt;getMethodAnnotation($method, $this-&gt;eventAnnotationClass);
          if (!$annotation instanceof Event || empty($annotation)) { continue; }
          $this-&gt;registerEvents($annotation, $class, $method-&gt;getName());
        }
      }
    }
  }

  /**
   *
   * @param    \MyNamespace\Annotations\Event $eventAnnotation
   * @param    string|object $class
   * @param    string $method
   * @return   \MyNamespace\Annotations\AnnotatedEventClassLoader
   */
  public function registerEvents($eventAnnotation, $class, $method) {
    $listener = is_object($class) ? $class : new $class();

    foreach ($eventAnnotation-&gt;getEvents() as $event) {
      $this-&gt;eventDispatcher-&gt;addListener(
        $event, array($listener, $method), $eventAnnotation-&gt;getPriority()
      );
    }
    return $this;
  }

  /**
   * Returns the full class name for the first class in the file.
   *
   * @param string $file A PHP file path
   *
   * @return string|false Full class name if found, false otherwise
   */
  protected function findClass($file) {
    $class = false;
    $namespace = false;
    $tokens = token_get_all(file_get_contents($file));
    for ($i = 0, $count = count($tokens); $i &lt; $count; $i++) {
      $token = $tokens[$i];

      if (!is_array($token)) { continue; }

      if (true === $class &amp;&amp; T_STRING === $token[0]) {
        return $namespace.'\\'.$token[1];
      }

      if (true === $namespace &amp;&amp; T_STRING === $token[0]) {
        $namespace = '';
        do {
          $namespace .= $token[1];
          $token = $tokens[++$i];
         } while ($i &lt; $count &amp;&amp; is_array($token) &amp;&amp; in_array($token[0], array(T_NS_SEPARATOR, T_STRING)));
       }

       if (T_CLASS === $token[0]) {
         $class = true;
       }

       if (T_NAMESPACE === $token[0]) {
         $namespace = true;
       }
     }

     return false;
   }
}</pre>
<p>Damit der Loader später auch seinen Dienst tut, muss er noch als Listener für das &#8220;kernel.request&#8221;-Event bekannt gemacht werden. Dafür habe ich die Datei &#8220;app/config/annotations.xml&#8221; mit folgendem Inhalt angelegt.</p>
<pre>&lt;?xml version="1.0" ?&gt;

&lt;container xmlns="http://symfony.com/schema/dic/services"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"&gt;

  &lt;parameters&gt;
    &lt;parameter key="myapp.event.loader.class"&gt;MyNamespace\Annotations\AnnotatedEventClassLoader&lt;/parameter&gt;
  &lt;/parameters&gt;

  &lt;services&gt;
    &lt;service id="myapp.event.loader"&gt;
      &lt;tag name="kernel.event_listener" event="kernel.request" method="init" /&gt;
      &lt;argument type="service" id="annotation_reader" /&gt;
      &lt;argument type="service" id="event_dispatcher" /&gt;
    &lt;/service&gt;
  &lt;/services&gt;
&lt;/container&gt;</pre>
<p>Die Konfiguration muss dann auch noch der AppKernel-Klasse mitgeteilt werden und damit ist der Loader eingebunden.</p>
<pre>class AppKernel extends Kernel {
  // other methods...

  public function registerContainerConfiguration(LoaderInterface $loader) {
    // ...
    $loader-&gt;load(__DIR__ . '/config/annotations.xml');
  }
}</pre>
<p>Annotations werden durch eigene Klassen verarbeitet und können dadurch mit beliebiger Logik versehen werden. Alles was einer Annotation als Parameter mitgegeben wird, bekommt die Klasse als Array im Constructor übergeben.</p>
<p>Für die Registrierung von Eventlistener brauchte ich nur die Events, die hier kommasepariert übergeben werden und gegebenenfalls noch die Priotität, in dem Fall optional. Die Klasse selber wird auch durch eine Annotation als solche gekennzeichnet.</p>
<pre>&lt;?php
namespace MyNamespace\Annotations;

/**
 * @Annotation
 */
class Event {
  private $events = array();
  private $priority = 0;

  public function __construct($options) {
    if (isset($options['value'])) {        
      $this-&gt;setEvents($options['value']);
    }

    $this-&gt;setPriority(
      isset($options['priority']) ? $options['priority'] : 0 );
  }

  public function getEvents() {
    return $this-&gt;events;
  }

  public function setEvents($events) {
    if(!is_array($events)) {
      $events = array_map('trim', explode(',', $events));
    }
    $this-&gt;events = $events;
    return $this;
  }

  public function getPriority() {
    return $this-&gt;priority;
  }

  public function setPriority($priority) {
    $this-&gt;priority = (int)$priority;
      return $this;
  }
}</pre>
<p>Nun sollte alles an PHP-Code und Konfiguration an seinem Platz sein, aber wie funktioniert das jetzt genau?</p>
<p>Durch das Event wird der Loader benachrichtigt, dass die Listener initialisiert werden sollen. Dazu wird das Verzeichnis &#8220;Listener&#8221; nach Klassen mit Annotations durchsucht, welche dann von der Annotation-Event-Klasse verarbeitet werden. Innerhalb des Loader werden dann die Listener für die Events registriert und können von da an verwendet werden.</p>
<p>Die Untersuchung des PHP-Codes funktioniert mit Reflections, was ansich immer den Ruf hat langsam zu sein. Der AnnotationReader verfügt über ein eigenes Caching und macht sich daher zeitlich nicht negativ bemerkbar.</p>
<p>Der Loader durchsucht das gesamte Verzeichnis in beliebiger Tiefe nach Dateien, daher bleibt man in der Namensvergabe frei.</p>
<p>Ein Listener könnte dann zum Beispiel so aussehen:</p>
<pre>&lt;?php
namespace MyNamespace\Bundle\Listener\Deep\Folder\Structure\Test;

use MyNamespace\Annotations\Event;

class Listener {
    /**
     * @Event("foo.bar, bar.foo", priority="1")
     * @param type $event
     */
    public function onFooBar1($event) {
        echo __METHOD__;
    }

    /**
     * @Event("foo.bar", priority="20")
     * @param type $event
     */
    public function onFooBar2($event) {
        echo __METHOD__;
    }
}</pre>
<p>Ein Aufruf aus dem Kontroller funktioniert dann wie gewohnt über den EventDispatcher, der fast überall als Service erreichbar ist.</p>
<pre>public function indexAction() {        
  $this-&gt;get('event_dispatcher')-&gt;dispatch('foo.bar');
}

// oder</pre>
<pre>public function indexAction() {
  $someEvent = new SomeEvent();       
  $this-&gt;get('event_dispatcher')-&gt;dispatch('foo.bar', $someEvent);
}</pre>
<p>Wie gesagt sind das meine ersten Versuche mit Symfony und der Code ist nicht optimiert. Die Funktionen des Loaders sollten noch weiter in Unterobjekte verteilt werden, damit das ganze noch flexibler wird und auch der gecodete Teil mit dem Verzeichnisnamen ist verbesserungfähig.</p>
<p>Ich konnte dabei wieder ein paar Sachen lernen und vielleich spart es ja dem einen oder anderen von euch etwas Zeit, falls ihr das braucht.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.ebene7.com/2012/02/27/symfony2-event-listener-ueber-annotations-registrieren/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>Es ist ein Model und es sieht gut aus &#8211; Der Observer</title>
		<link>https://blog.ebene7.com/2010/05/07/es-ist-ein-model-und-es-sieht-gut-aus-der-observer/</link>
		<comments>https://blog.ebene7.com/2010/05/07/es-ist-ein-model-und-es-sieht-gut-aus-der-observer/#comments</comments>
		<pubDate>Fri, 07 May 2010 05:00:06 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Tutorial]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[CustomLibrary]]></category>
		<category><![CDATA[Custom_Model]]></category>
		<category><![CDATA[Data Mapper]]></category>
		<category><![CDATA[Design Patterns]]></category>
		<category><![CDATA[Entwurfsmuster]]></category>
		<category><![CDATA[Interface]]></category>
		<category><![CDATA[Listeners]]></category>
		<category><![CDATA[Model]]></category>
		<category><![CDATA[MVC]]></category>
		<category><![CDATA[Observable]]></category>
		<category><![CDATA[Observer]]></category>
		<category><![CDATA[SPL]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=434</guid>
		<description><![CDATA[Zum Abschluss dieser Woche werden wir heute noch schnell das Observer-Pattern verbauen und dazu das passende Interface SplSubject implementieren. In dem Zusammenhang findet dann auch die Klasse SplObjectStorage eine sinnvolle Verwendung. Zuerst erweitern wir das Interface Custom_Model_Interface um SplSubject und &#8230; <a href="https://blog.ebene7.com/2010/05/07/es-ist-ein-model-und-es-sieht-gut-aus-der-observer/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Zum Abschluss dieser Woche werden wir heute noch schnell das <a href="http://de.wikipedia.org/wiki/Observer_%28Entwurfsmuster%29" target="_blank">Observer-Pattern</a> verbauen und dazu das passende <a href="http://www.php.net/manual/de/class.splsubject.php" target="_blank">Interface SplSubject</a> implementieren. In dem Zusammenhang findet dann auch die Klasse <a href="http://www.php.net/manual/de/class.splobjectstorage.php" target="_blank">SplObjectStorage</a> eine sinnvolle Verwendung.</p>
<p><span id="more-434"></span>Zuerst erweitern wir das Interface Custom_Model_Interface um SplSubject und ein paar eigene Methoden.</p>
<pre>&lt;?php
interface Custom_Model_Interface
    extends ArrayAccess,
            Iterator,
            Countable,
            SplSubject
{
  public function mark();
  public function modified();
  public function cleanModified();
  public function modifiedKeys();
}</pre>
<p>Anschliessend kümmern wir uns um die Klassen Custom_Model und bauen alles Nötige ein.</p>
<pre>&lt;?php
class Custom_Model implements Custom_Model_Interface
{
  // ...
  protected $_observers;
  protected $_modified;

  public function attach(SplObserver $observer) {}
  public function detach(SplObserver $observer) {}
  public function notify() {}

  public function mark() {}
  public function modified() {}
  public function cleanModified() {}
  public function modifiedKeys() {}
  // ...
}</pre>
<p>So weit, so gut! Die ersten drei Methoden <code>attach()</code>, <code>detach()</code> und <code>notify()</code> werden durch das Interface SplSubject vorgeschrieben und sind die Schnittstelle, um Observer am Objekt zu registrieren, sie zu entfernen oder zu benachrichtigen.</p>
<p>Mit den vier weiteren können wir den Status des Objektes setzen oder kontrollieren. Die beiden protected Eigenschaften enthalten eine Liste von Typ SplObjectStorage für die Observer und ein einfaches Array für den jeweiligen Status eines Feldes.</p>
<p>Bevor wir das verwenden können, müssen wir es im Konstruktor initialisieren.</p>
<pre>public final function __construct()
{
  $this-&gt;_observers = new SplObjectStorage();
  $this-&gt;cleanModified();
  // ...
}</pre>
<p>Der Vorteil von SplObjectStorage ist der, dass jedes Objekt nur einmal darin vorkommen kann und wir uns um die Steuerung keine Gedanken machen müssen. Das macht dann auch das Hinzufügen und Entfernen eines Observers sehr einfach.</p>
<pre>public function attach(SplObserver $observer)
{
  $this-&gt;_observers-&gt;attach($observer);
  return $this;
}

public function detach(SplObserver $observer)
{
  $this-&gt;_observers-&gt;detach($observer);
  return $this;
}</pre>
<p>Mir zaubert das immer ein breites Grinsen ins Gesicht, wenn eine Aufgabe mit so wenig Code gelöst werden kann und der Doc-Block teilweise länger ist als die Funktion.</p>
<p>Aber nun wieder zum Thema. Bevor wir uns an die wirklich einfache Benachrichtigung machen, werde ich noch schnell auf die Sache mit der Statuskontrolle eingehen. Eine Aktion, z.B. <code>_set()</code> setzt den &#8220;modified&#8221;-Status eines Feldes, so dass jeder Schreibzugriff auf das Modell erkennbar wird.</p>
<p>Dadurch haben wir später die Möglichkeit, nur zu benachrichtigen, wenn es nötig ist oder auch nur die Felder zu speichern, die sich verändert haben.</p>
<p>Um eine Änderung bekannt zu machen verwenden wir <code>mark()</code>.</p>
<pre>public function mark($key)
{
  if($this-&gt;keyExists($key)) {
    $this-&gt;_modified[$this-&gt;_mapKey($key)] = true;
  }
  return $this;
}</pre>
<p>Die Methode erwartet den Namen eines existierenden Feldes und setzt ein Flag im Array.</p>
<p>Um den Status des Objektes oder eines einzelnen Feldes abfragen zu können haben wir dann <code>modified()</code>.</p>
<pre>public function modified($key = null)
{
  if(null !== $key) {
    return isset($this-&gt;_modified[$this-&gt;_mapKey($key)]);
  }
  return count($this-&gt;_modified) &gt; 0;
}</pre>
<p>Durch die Angabe des Parameters $key wird ein Feld abgefragt, ansonsten der Gesamtstatus. Nach dem selben Prinzip funktioniert dann auch <code>cleanModified()</code>, um den Status wieder zurück zu setzen.</p>
<pre>public function cleanModified($key = null)
{
  if(null != $key) {
    unset($this-&gt;_modified[$this-&gt;_mapKey($key)]);
  } else {
    $this-&gt;_modified = array();
  }
  return $this;
}</pre>
<p>Falls wir eine Liste der veränderten Felder brauchen, dann ist dafür <code>modifiedKeys()</code> vorgesehen.</p>
<pre>public function modifiedKeys()
{
  $keys = array();

  foreach($this-&gt;_keys as $key) {
    if($this-&gt;modified($key)) {
      $keys[] = $key;
    }
  }

  return $keys;
}</pre>
<p>Nachdem wir das alles durch haben, können wir uns nun <code>notify()</code> widmen, bevor wir unser Werk an ein paar Beispielen testen können.</p>
<pre>public function notify()
{
  if($this-&gt;modified()) {
    foreach($this-&gt;_observers as $observer) {
      $observer-&gt;update($this);
    }
  }
  $this-&gt;cleanModified();
  return $this;
}</pre>
<p>Die Methode macht im Prinzip nichts weiter, als bei allen in der Liste befindlichen Observer-Objekten <code>update()</code> aufzurufen und sich selbst als Parameter mitzugeben. Dadurch weiß die Observerklasse gleich, welches Objekt sich verändert hat.</p>
<p>Das folgende Beispiel zeigt einen einfachen Beobachter, der nur den Klassennamen von $subject ausgibt und eine Liste der geänderten Felder, wenn das Objekt vom Typ Custom_Model ist.</p>
<pre>class myObserver implements SplObserver
{
  public function update(SplSubject $subject)
  {
    echo get_class($subject) . ' hat sich verändert&lt;br/&gt;';
    if($subject instanceof Custom_Model) {
      print_r($subject-&gt;modifiedKeys());
    }
  }
}

$model = new Person();
$model-&gt;attach(new myObserver());
$model-&gt;setId(42)
      -&gt;setVorname('Bart');

$model-&gt;notify();</pre>
<p>Das interessante an dem Observer-Muster ist die lose Kopplung der Objekte und die Tatsache, dass ein Observer beliebig viele Subjekte beobachten kann und umgekehrt ein Subjekt beliebig viele Observer haben kann.</p>
<p>So, das war es dann auch schon für diese Woche und zu diesem Thema. Wie ich einst schon sagte, ist es ein sehr ergiebiges Thema, weil sich viele Techniken in sinnvoller Verbindung anwenden lassen. Bislang haben wir trotzdem erst nur einen Datenklumpen mit etwas Dekoration.</p>
<p>Richtig interessant wird es dann, wenn wir die Models über Mapper-Klassen laden und speichern können, aber das wird dann evtl. das Thema einer neuen Serie&#8230;</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.ebene7.com/2010/05/07/es-ist-ein-model-und-es-sieht-gut-aus-der-observer/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Event-Handling bei Magento</title>
		<link>https://blog.ebene7.com/2010/05/06/event-handling-bei-magento/</link>
		<comments>https://blog.ebene7.com/2010/05/06/event-handling-bei-magento/#comments</comments>
		<pubDate>Thu, 06 May 2010 05:00:20 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[Notiz an mich]]></category>
		<category><![CDATA[Tipps und Tricks]]></category>
		<category><![CDATA[Eventhandling]]></category>
		<category><![CDATA[Konfiguration]]></category>
		<category><![CDATA[Listeners]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[Observer]]></category>
		<category><![CDATA[Shop]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=744</guid>
		<description><![CDATA[Wie ich ja vor kurzem schon berichtet habe, bin ich dabei mich in die Shopsoftware Magento einzuarbeiten und dabei stolpere ich noch hin und wieder über das eine oder andere Feature. So zum Beispiel hatte ich den Fall, dass ich &#8230; <a href="https://blog.ebene7.com/2010/05/06/event-handling-bei-magento/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Wie ich ja vor kurzem schon berichtet habe, bin ich dabei mich in die Shopsoftware Magento einzuarbeiten und dabei stolpere ich noch hin und wieder über das eine oder andere Feature. So zum Beispiel hatte ich den Fall, dass ich einen eigenen Observer nach einer Speicheraktion verwendet habe, der aber nicht im Adminbereich reagierte.</p>
<p>Die Lösung ist deratig einfach, wenn man es weiß&#8230; Die Einstellung für das jeweilige Event muss natürlich im richtigen Scope in der config.xml gemacht werden.</p>
<p>Ist der Beobachter nun also global eingestellt, klappt es auch in allen Bereichen. Andersherum lässt sich so aber auch eine unterschiedliche Verarbeitung für das selbe Ereignis einstellen.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.ebene7.com/2010/05/06/event-handling-bei-magento/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Was ist schlecht an public Properties?</title>
		<link>https://blog.ebene7.com/2010/01/05/was-ist-schlecht-an-public-properties/</link>
		<comments>https://blog.ebene7.com/2010/01/05/was-ist-schlecht-an-public-properties/#comments</comments>
		<pubDate>Tue, 05 Jan 2010 18:00:15 +0000</pubDate>
		<dc:creator>Daniel</dc:creator>
				<category><![CDATA[Entwicklung]]></category>
		<category><![CDATA[Grundlagen]]></category>
		<category><![CDATA[Interceptor]]></category>
		<category><![CDATA[Magic Methods]]></category>
		<category><![CDATA[Observer]]></category>

		<guid isPermaLink="false">http://blog.ebene7.com/?p=163</guid>
		<description><![CDATA[Immer wieder kommt während der Entwicklung die Diskussion auf, ob die Sichtbarkeit der Objekteigenschaften public, protected oder private sein sollten. Aber welche Vor- und Nachteile haben denn nun die einzelnen Einstellungen? <a href="https://blog.ebene7.com/2010/01/05/was-ist-schlecht-an-public-properties/">Weiterlesen <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>Immer wieder kommt während der Entwicklung die Diskussion auf, ob die Sichtbarkeit der Objekteigenschaften public, protected oder private sein sollte.</p>
<p>Aber welche Vor- und Nachteile haben denn nun die einzelnen Einstellungen?</p>
<p><span id="more-163"></span><br />
&#8220;Lass es uns doch einfach halten&#8221;, &#8220;Das macht doch viel mehr Arbeit&#8221; oder &#8220;Mehr soll dieses Objekt nie können&#8221; und &#8220;Unsere Designer kennen das doch nur so&#8221; sind oft die Argumente warum die Eigenschaften public sein sollten.</p>
<p>Persönlich bin ich immer für eine saubere <a href="http://de.wikipedia.org/wiki/Datenkapselung_(Programmierung)" target="_blank">Datenkapselung</a> und Verwendung von <a href="http://de.wikipedia.org/wiki/Zugriffsfunktion" target="_blank">Zugriffsmethoden</a>.</p>
<p>Zunächst ist es richtig, dass die Programmierung der Zugriffsmethoden mehr Arbeit macht, als einfach eine öffentliche Variable zu verwenden. Viele <a href="http://de.wikipedia.org/wiki/Integrierte_Entwicklungsumgebung" target="_blank">IDEs</a>, z.B. <a href="http://de.wikipedia.org/wiki/Eclipse_(IDE)" target="_blank">Eclipse</a> können diese Methoden aber auch automatisch generieren, so dass wirklich nur noch wenige Mausklicks nötig sind.</p>
<p>Viele andere Sprachen bieten die Typisierung von Variablen standardmäßig an, so dass man sich dort schon weitestgehend darauf verlassen kann welcher Typ vorliegt. PHP zum Beispiel bietet das (bislang) nicht und wir müssen uns selber darum kümmern.</p>
<p>Das schützt uns aber auch noch nicht davor, dass statt dem geforderten Objekttyp ein NULL-Wert gesetzt ist und wir mit einem Methodenaufruf einen Laufzeitfehler auslösen. Solche Anforderungen können wir dann in unseren Zugriffsmethoden umsetzen.</p>
<p>Wird einer Set-Methode ein NULL-Wert übergeben, so können wir entsprechend darauf reagieren und eine <a href="http://de.wikipedia.org/wiki/Exception" target="_blank">Exception</a> werfen.</p>
<p>Ebenso können wir auch der Get-Methode eine nützliche Logik implementieren. Ist die Eigenschaft beim Methodenaufruf noch nicht gesetzt, können wir an dieser Stelle z.B. ein (<a href="http://de.wikipedia.org/wiki/Nullobjekt_(Entwurfsmuster)" target="_blank">Null</a>-)Objekt erzeugen, einen bestimmten Wert aus der Datenbank laden oder einfach einen Standardwert zurückgeben.</p>
<p>Oftmals ergibt sich auch die Anforderung, auf Veränderungen an einem Objekt reagieren zu müssen. Dafür bietet sich das <a href="http://de.wikipedia.org/wiki/Observer_(Entwurfsmuster)" target="_blank">Observer/Beobachter-Entwurfsmuster</a> an.</p>
<p>Die Beobachter müssen über eine Veränderung benachrichtigt werden und auch das funktioniert über die Zugriffsmethoden. Würden wir zu einem späteren Zeitpunkt feststellen, dass wir das Objekt beobachten müssen und dafür eine nachträgliche Veränderung der Schnittstelle erforderlich ist, bringt das meist sehr viel Arbeit und potentielle Fehlerquellen mit sich, da alle Stellen im Programm überarbeitet werden müssen, an denen das Objekt verwendet wird.</p>
<p>Es gibt natürlich auch immer wieder Situationen, die öffentliche Eigenschaften verlangen oder in denen die Handhabung einfacher wird, z.B. weil schon 150 Templates damit arbeiten und nicht extra angepasst werden sollen.</p>
<p>Verschiedene Sprachen bieten dafür Möglichkeiten an, um direkte Zugriffe auf Objekteigenschaften an Zugriffsmethoden zu delegieren.</p>
<p>Bei PHP ab Version 5 sind das die sogenannten <a href="http://de2.php.net/manual/de/language.oop5.magic.php" target="_blank">Magischen Methoden</a> oder Interceptor-Methoden <a href="http://de2.php.net/manual/de/language.oop5.overloading.php#language.oop5.overloading.members" target="_blank">__get() und __set()</a>.</p>
<p>Alles in allem haben wir bei der Programmierung unserer Klassen etwas mehr Aufwand, aber dafür weniger Stress, wenn sich unsere Anwendung in eine Richtung weiterentwickelt, die wir heute noch nicht vorhersehen können.</p>
]]></content:encoded>
			<wfw:commentRss>https://blog.ebene7.com/2010/01/05/was-ist-schlecht-an-public-properties/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
