Simone: Datumrechnung

0 55

Datumrechnung

Simone
  • php
  1. 0
    EKKi
    1. 0
      Simone
      1. 0
        Christoph Jeschke
        1. 0
          Tom
          1. 0
            Christoph Jeschke
            1. 0
              Tom
            2. 0
              Simone
              1. 0
                Christoph Jeschke
                1. 0
                  Tom
                  1. 0
                    Christoph Jeschke
                    • menschelei
                    1. 0
                      Tom
                      1. 0
                        Christoph Jeschke
                        1. 0
                          Tom
                  2. 0
                    Sven Rautenberg
                    1. 0
                      Tom
                      1. 0
                        EKKi
                        • meinung
          2. 2

            Lebensdauer von {Datenbank-,File-,...}Handles in PHP

            Christian Seiler
            1. 0
              Tom
              1. 0
                Sven Rautenberg
                1. 0

                  Lebensdauer von {Datenbank-,File-,...} Handles in PHP

                  Tom
                  1. 0
                    EKKi
                    • meinung
                    1. 0
                      Tom
                2. 0
                  Edgar Ehritt
            2. 0
              Tom
              1. 0
                EKKi
                • meinung
                1. 0

                  Genau nachfragen ist hier verboten?

                  Tom
                  • zu diesem forum
                  1. 0
                    flowh
                    1. 0
                      Tom
                      1. 0
                        Edgar Ehritt
                        1. 0
                          Tom
              2. 8

                Interna von Variablen und Ressourcen, Lebensdauer, GC

                Christian Seiler
                1. 0
                  Tom
                2. 0

                  Wo werden Name und (Meta-)Daten der Variable verbunden?

                  Tom
                  1. 0
                    dedlfix
                    1. 0
                      Tom
                      1. 0
                        dedlfix
                        1. 0
                          Tom
                          1. 0
                            dedlfix
                            1. 0
                              Tom
                              1. 0
                                Christian Seiler
                  2. 0
                    Christian Seiler
                    1. 0
                      Christian Seiler
                      1. 0
                        Tom
                3. 0
                  Edgar Ehritt
                  • meinung
                  1. 0
                    Christian Seiler
                    1. 0

                      Interna von Variablen

                      Edgar Ehritt
                      • menschelei
                      1. 0
                        Christian Seiler
                    2. 0
                      Tom
                4. 0
                  Bademeister
                  1. 0
                    Christian Seiler
                    1. 0
                      Bademeister
                      1. 0
                        Christian Seiler
                    2. 0
                      Kai345
  2. 0
    Edgar Ehritt

N'Abend Zusammen,

ich hänge seit einigen Stunde leicht mit dem Kopf am Brett, daher würde ich mich sehr über Hilfe freuen.

Mein Problem:

Ich habe einen Datensatz mit jeweils einem Erstellungdatum im Unixformat, dieses soll mir nach der Erstellung 30 Tage lang in einer Liste angezeigt werden. Nach 31 Tagen soll es einfach nicht mehr angezeigt werden.

Mein bisheriger Versuch ist:

date <= date_sub(now(), INTERVAL 30 DAY)

Jedoch funktionert es nicht der Code nicht. Habe ich einen totalen Denkfehler oder?

LG
Simone

  1. Mahlzeit Simone,

    Mein bisheriger Versuch ist:

    date <= date_sub(now(), INTERVAL 30 DAY)

    Wo genau ist das PHP-Code? Das sieht eher nach SQL-Code aus ...

    Jedoch funktionert es nicht der Code nicht. Habe ich einen totalen Denkfehler oder?

    Ja. Entweder hast Du nämlich ein massives Syntaxproblem in PHP (das sollte Dir aber bei entsprechender Einstellung des error_reporting() angezeigt werden) oder Du hast ein Datenbankproblem - kein PHP-Problem.

    Liefere also zunächst die fehlenden Informationen (z.B. Fehlermeldungen usw.), dann könnte man Dir auch helfen ...

    MfG,
    EKKi

    --
    sh:( fo:| ch:? rl:( br:> n4:~ ie:% mo:} va:) de:] zu:) fl:{ ss:) ls:& js:|
    1. Hi EKKim

      mittlerweile habe ich bereits eine Lösung gefunden, jedoch gibt er mir jetzt für jedes einzelne Datum eine Liste aus... Das möchte ich noch beseitigen weiß aber nicht wie.

      ---Header---
      -----------------------
      Kunde 1   3 Tage
      Kunde 2   3 Tage
      ---Header---
      -----------------------
      Kunde 3   5 Tage
      etc.

        setlocale(LC_TIME, 'de_DE');  
        $datumonline = date("m.d.Y");  
        list($mon,$tag,$jahr)=explode(".",$datumonline);  
        for($i=0;$i<40;$i++)  
        {  
        $timestamp[$i] = mktime(0,0,0,$mon,$tag-$i,$jahr);  
        $timestamp2[$i] = mktime(23,59,59,$mon,$tag-$i,$jahr);  
        }  
        for($i=0;$i<40;$i++)  
        {  
      			  
      	$sql = "SELECT * FROM  
                  (SELECT * FROM ".$db_table."_".$_GET['event']." WHERE position = 'SC' ORDER BY id ASC LIMIT 0,$sc)  
                ".$_GET['event']." WHERE check_in = 'nicht eingecheckt' AND calculation = 'nicht bezahlt' AND booking_date <= '$timestamp2[$i]' AND booking_date >= '$timestamp[$i]'  
                ORDER BY booking_date DESC ;";  
      	$result = mysql_query($sql) or die( mysql_error() );  
      			  
        $list = mysql_fetch_row(mysql_query("SELECT COUNT(customer_event) FROM ".$db_table."_".$_GET['event']." WHERE position = 'SC' AND calculation = 'nicht bezahlt' AND booking_date <= '$timestamp2[$i]' AND booking_date >= '$timestamp[$i]'"));  
       	$if = $list[0];  
        
        if ($if > 0)  
          {  
      		echo "<thead>",$list[0],"<tr>  
          <th colspan=11><center>Die letzten 40 Tage</center></th>  
                 </tr>  
          	  	 <tr>  
            	    <th><center>#</center></th>  
        				  <th>Name, Vorname</th>  
            			<th></th>  
           				<th>Charakter</th>  
           				<th></th>  
            			<th><center>EUR</center></th>  
            			<th><center>AGB</center></th>  
            			<th></th>  
            			<th></th>  
            			<th></th>  
            			<th></th>  
          				</tr>  
        				 </thead>  
        				  <tbody>";  
                  }  
      			  	  
                include("list_customer_function.php");  
        } 
      
      1. Guten Tag,

        mittlerweile habe ich bereits eine Lösung gefunden, jedoch gibt er mir jetzt
        für jedes einzelne Datum eine Liste aus... Das möchte ich noch beseitigen
        weiß aber nicht wie.

        Nun, derzeit läufst du in der for-Schleife ja auch jeden der 40 Tage durch und erzeugst einen neuen Tabellenabschnitt mit Tabellenkopf.

        Mir ist auch noch nicht ganz klar, was du mit $result machst. Oder verwendest du diese in list_customer_function.php?

        Dein Code erscheint mir außerdem extrem ineffizient, da du statt einer Abfrage, welche die Ergebnisse der letzten 40 Tagezurückliefert, 40 Abfragen machst, die jeweils n Einträge zurückliefert. Du selektierst auch in jedem Durchlauf die Anzahl der gefundenen Einträge neu. Das kannst du alles mit einer Abfrage erfahren, z.B. in dem du mysql_num_rows() auf die Gesamtergebnismenge anwendest.

        Gruß
        Christoph Jeschke

        --
        Zend Certified Engineer
        Certified Urchin Admin
        1. Hello,

          Nun, derzeit läufst du in der for-Schleife ja auch jeden der 40 Tage durch und erzeugst einen neuen Tabellenabschnitt mit Tabellenkopf.

          ...und neuem Request an die Datenbank, ohne das Resultset wieder freizugeben.
          Damit wird der Speicher von Datenbank und API vollgemüllt und irgendwann kommt dann die Meldung, dass keine Handles für Resultsets mehr zur Verfügung stehen.

          Liebe Grüße aus dem schönen Oberharz

          Tom vom Berg

          --
          Nur selber lernen macht schlau
          http://bergpost.annerschbarrich.de
          1. Guten Tag,

            ...und neuem Request an die Datenbank, ohne das Resultset wieder freizugeben.
            Damit wird der Speicher von Datenbank und API vollgemüllt und irgendwann kommt
            dann die Meldung, dass keine Handles für Resultsets mehr zur Verfügung stehen.

            Das fällt wohl unter "Dein Code erscheint mir außerdem extrem ineffizient" :-)

            Gruß
            Christoph Jeschke

            --
            Zend Certified Engineer
            Certified Urchin Admin
            1. Hello,

              ...und neuem Request an die Datenbank, ohne das Resultset wieder freizugeben.
              Damit wird der Speicher von Datenbank und API vollgemüllt und irgendwann kommt
              dann die Meldung, dass keine Handles für Resultsets mehr zur Verfügung stehen.

              Das fällt wohl unter "Dein Code erscheint mir außerdem extrem ineffizient" :-)

              Stimmt.
              Ich habe es auch nur nochmal substantiiert, weil dies ein Standardfehler ist, der selbst Profis immer wieder passiert. Wenn dann ihre tolle Site aus der Laborumgebung in die Wirklichkeit umgezogen sit, steht der Server plötzlich und keiner weiß warum.

              Auch in etablierten Klassen habe ich diese Fehler schon gefunden.

              Liebe Grüße aus dem schönen Oberharz

              Tom vom Berg

              --
              Nur selber lernen macht schlau
              http://bergpost.annerschbarrich.de
            2. Hallo Christoph,

              okay, wie könnte ich das ganze etwas effizenter Gestalten (Schlagwort)? und das result wird in der Including verwendet.

              LG
              Simone

              1. Guten Tag,

                okay, wie könnte ich das ganze etwas effizenter Gestalten (Schlagwort)? und das
                result wird in der Including verwendet.

                in dem du
                i)   in _einem_ Query _alle_ Datensätze der vergangenen 40 Tage selektierst
                ii)  anhand des Resultsets die Anzahl der gefundenen Datensätze selektiertst
                iii) danach das Zimmer^WResultset wieder aufräumst

                Gruß
                Christoph Jeschke

                --
                Zend Certified Engineer
                Certified Urchin Admin
                1. Hello,

                  iii) danach das Zimmer^WResultset wieder aufräumst

                  Was kaum einen Unterschied macht, wenn man in einem Script nur eine Reslutset benötigt.

                  Benutzt man aber (aufgrund von Schleifen) dasselbe Handel für ein Resultset mehrmals, dann muss man es, bevor man es neu belegt, freigeben. Anderenfalls würde i.d.R. bei geteilten Applikationen die Zugriffsmöglichkiet auf das vorherige Resultset verloren gehen, obwohl es noch im Speicher steht. Das nennt man dann 'lost Handle'. Dieser Fehler wird erst beseitigt, wenn eine vollständige Integration (i.d.r: dann objektoreintiert) zwischen den zwei Diensten besteht.

                  Wird das Handle dann in der Leitapplikation gelöscht oder neu belegt, gibt deren Maschinereir die Verknüpfung zur anderen Applikation vorher automatisch wieder frei. Das ist aber in PHP bisher weder bei Dateihandles noch bei Resultsets aud der Datenbank der Fall.

                  Liebe Grüße aus dem schönen Oberharz

                  Tom vom Berg

                  --
                  Nur selber lernen macht schlau
                  http://bergpost.annerschbarrich.de
                  1. Guten Tag,

                    Reslutset

                    ^^^^

                    Also das solltest du besser nicht zu Simone sagen ;-)

                    Gruß
                    Christoph Jeschke

                    --
                    Zend Certified Engineer
                    Certified Urchin Admin
                    1. Hello,

                      Reslutset
                          ^^^^

                      Also das solltest du besser nicht zu Simone sagen ;-)

                      *hups* hat das in einer anderen Sprache eine bestimmte Bedeutung?

                      Liebe Grüße aus dem schönen Oberharz

                      Tom vom Berg

                      --
                      Nur selber lernen macht schlau
                      http://bergpost.annerschbarrich.de
                      1. Guten Tag,

                        *hups* hat das in einer anderen Sprache eine bestimmte Bedeutung?

                        Slut

                        Gruß
                        Christoph Jeschke

                        --
                        Zend Certified Engineer
                        Certified Urchin Admin
                        1. Hello,

                          *hups* hat das in einer anderen Sprache eine bestimmte Bedeutung?

                          Slut

                          Oh, das ist peinlich. Das war aber wirklich nur ein Tippfehler. ;-)

                          Liebe Grüße aus dem schönen Oberharz

                          Tom vom Berg

                          --
                          Nur selber lernen macht schlau
                          http://bergpost.annerschbarrich.de
                  2. Moin!

                    »» iii) danach das Zimmer^WResultset wieder aufräumst

                    Was kaum einen Unterschied macht, wenn man in einem Script nur eine Reslutset benötigt.

                    Benutzt man aber (aufgrund von Schleifen) dasselbe Handel für ein Resultset mehrmals, dann muss man es, bevor man es neu belegt, freigeben. Anderenfalls würde i.d.R. bei geteilten Applikationen die Zugriffsmöglichkiet auf das vorherige Resultset verloren gehen, obwohl es noch im Speicher steht. Das nennt man dann 'lost Handle'. Dieser Fehler wird erst beseitigt, wenn eine vollständige Integration (i.d.r: dann objektoreintiert) zwischen den zwei Diensten besteht.

                    Du erzählst, im Hinblick auf PHP, an dieser Stelle ebenfalls Unsinn. Hat dir Christian ja aber auch schon gesagt.

                    Wird das Handle dann in der Leitapplikation gelöscht oder neu belegt, gibt deren Maschinereir die Verknüpfung zur anderen Applikation vorher automatisch wieder frei. Das ist aber in PHP bisher weder bei Dateihandles noch bei Resultsets aud der Datenbank der Fall.

                    Hä?

                    - Sven Rautenberg

                    1. Hello,

                      Du erzählst, im Hinblick auf PHP, an dieser Stelle ebenfalls Unsinn. Hat dir Christian ja aber auch schon gesagt.

                      Aber er hat es noch nicht bewiesen.

                      Liebe Grüße aus dem schönen Oberharz

                      Tom vom Berg

                      --
                      Nur selber lernen macht schlau
                      http://bergpost.annerschbarrich.de
                      1. Mahlzeit Tom,

                        »» Du erzählst, im Hinblick auf PHP, an dieser Stelle ebenfalls Unsinn. Hat dir Christian ja aber auch schon gesagt.

                        Aber er hat es noch nicht bewiesen.

                        Das muss er hier in diesem Forum auch in keinster Weise ... Fachsimpeleien zur Kernstruktur von PHP sind IMHO auch dort besser aufgehoben.

                        MfG,
                        EKKi

                        --
                        sh:( fo:| ch:? rl:( br:> n4:~ ie:% mo:} va:) de:] zu:) fl:{ ss:) ls:& js:|
          2. Hallo Tom,

            ...und neuem Request an die Datenbank, ohne das Resultset wieder freizugeben.

            Nein, das passiert hier nicht. Da die gleiche Variable wieder überschrieben wird, wird das alte Result-Set durchaus freigegeben, PHP macht das beim Vernichten der Resource automatisch. Du solltest nicht über das Ziel hinausschießen und (wenn auch unabsichtlich) Fehlinformationen verbreiten, wenn Du schlechten Code kritisierst, das ist auf Lange sicht nämlich auch nicht hilfreich. Daher mal als Merksatz:

            Wenn man bei PHP irgend eine Art Handle hat (Resource für Datenbankverbindung, Datenbankresult, Datei, ... oder mit neueren APIs à la PDO eben Objekte statt Resourcen) und dieses Handle wird nicht mehr benötigt (weil es eben mit keiner Variable mehr fest verbunden ist), dann kümmert sich PHP alleine um das Aufräumen des Handles. Genauer gesagt ruft PHP nur eine von der Erweiterung vorher festgelegte Funktion auf, die das dann erledigt. In fast allen Fällen sind Funktionen wie mysql_free_result() überflüssig. Es gibt Ausnahmen, aber die treten bei typischer Verwendung von solchen Dingen sehr selten auf.

            Um das mal zu erläutern:

            for ($i = 0; $i < 100; $i++) {  
              $result = mysql_query ("SELECT * FROM foobar");  
            }
            

            Am Anfang der Schleife ist $result NULL. Wenn die erste Iteration der Schleife vorbei ist, ist $result ein Zeiger auf das erste Result-Set. Wenn nun die Schleife das nächste mal iteriert wird, will PHP $result überschreiben. Dabei gibt PHP das frei, was vorher in $result enthalten war, nämlich das erste Result-Set. Danach erst wird das zweite Result-Set an die Variable zugewiesen. Man hat also zeitgleich nur zwei Resultsets herumflattern (das alte + ein neues, das Resultat von mysql_query ist, was noch in irgend einer temporären Kiste rumfliegt, bevor es zugewiesen wird) - und bestimmt keine 100. Hier ist es absolut nicht nötig, das alte Result-Set wieder freizugeben.

            Anderes Beispiel:

            function foobar () {  
              $result = mysql_query ("SELECT * FROM foobar");  
              return mysql_fetch_row ($result);  
            }
            

            Auch hier ist es nicht nötig, das Result-Set explizit wieder freizugeben. Denn am Ende der Funktion wird die Variable $result zerstört und damit die letzte Referenz auf das Result-Set -> PHP erledigt das automatisch.

            Weiteres Beispiel:

            $row = mysql_fetch_row (  
              mysql_query ("SELECT * FROM foobar")  
            );
            

            Auch hier ist es nicht nötig, das Result-Set explizit wieder freizugeben: Das Ergebnis von mysql_query wird sowieso nur temporär im Speicher behalten und am Ende des Aufrufs von mysql_fetch_row wird das Result-Set automatisch wieder freigegeben, weil's nirgendwo mehr referenziert wird.

            Wo es dagegen wirklich nötig ist, das Result-Set explizit wieder freizugeben ist in Fällen, in denen man sich nicht sicher sein kann, das das Result-Set nicht auch woanders noch referenziert wird - z.B. wenn man weitere Referenzen in irgendwelchen anderen Variablen speichert (aus welchen Gründen auch immer) und man sich nicht darauf verlassen will, dass diese anderen Variablen auch immer aus dem Scope geraten. Mir fällt jedoch ad-hoch kein sinnvolles Beispiel ein, wo dies nötig sein könnte, ich wollte es nur der Vollständigkeit halber mal erwähnen. Das ändert jedoch nichts an der Tatsache, dass dies in den meisten Fällen nicht nötig ist.

            Dies soll selbstverständlich nicht heißen, dass die Beispiele in meinem Posting nicht trotzdem schlechter Code sind - aber das sind sie eben aus anderen Gründen, nicht wegen irgendwelchen Dingen, die angeblich noch im Speicher herumgeistern. Diese Gründe wären vor allem mangelnde Fehlerbehandlung (es wird nicht geprüft ob mysql_query überhaupt erfolgreich ist und ein Result-Set zurückliefert) und zumindest im ersten Beispiel ist es extrem fraglich, ob es effizient ist, den gleichen Query in einer Schleife wiederholt auszuführen.

            Viele Grüße,
            Christian

            --
            Mein "Weblog" [RSS]
            Using XSLT to create JSON output (Saxon-B 9.0 for Java)
            »I don't believe you can call yourself a web developer until you've built an app that uses hyperlinks for deletion and have all your data deleted by a search bot.«
                        -- Kommentar bei TDWTF
            1. Hello,

              Hallo Tom,

              ...und neuem Request an die Datenbank, ohne das Resultset wieder freizugeben.

              Nein, das passiert hier nicht. Da die gleiche Variable wieder überschrieben wird, wird das alte Result-Set durchaus freigegeben, PHP macht das beim Vernichten der Resource automatisch.

              Ich werde das genauer untersuchen. Es widerspricht allerdings der klassischen Lehrmeinung und den bisherigen Erkenntnissen. Wie sprechen nicht von PHP-OOP, dise nur nur zur Erinnerung.

              Und bezüglich File-Handles ist der kleine Versuch jedenfalls schon recht interessant.

              <?php   ### filehandle.php ###

              for ($i=1; $i < 101; $i++)
              {
                  $fh = fopen(__FILE__, 'r');
                  echo "$i. Filehandle: $fh <br>\r\n";
              }

              ?>

              Das ist natürlich jetzt nur rein äußerlich betrachet. Man muss reingucken.
              Es wird eine Weile dauern, das Innenleben von PHP entsprechend zu untersuchen ;-)

              Liebe Grüße aus dem schönen Oberharz

              Tom vom Berg

              --
              Nur selber lernen macht schlau
              http://bergpost.annerschbarrich.de
              1. Moin!

                »» Nein, das passiert hier nicht. Da die gleiche Variable wieder überschrieben wird, wird das alte Result-Set durchaus freigegeben, PHP macht das beim Vernichten der Resource automatisch.

                Ich werde das genauer untersuchen. Es widerspricht allerdings der klassischen Lehrmeinung und den bisherigen Erkenntnissen. Wie sprechen nicht von PHP-OOP, dise nur nur zur Erinnerung.

                Nur weil PHP auch OOP kann, heißt das ja nicht, dass diese grundsätzlichen Verhaltensweisen nur dort angewendet werden.

                Man darf der Speicherverwaltung durchaus vertrauen. Erst wenn dann trotzdem kein RAM mehr verfügbar ist, sollte man sich Gedanken machen, vorher ist das unnötige Optimierung ohne Sinn.

                Und bezüglich File-Handles ist der kleine Versuch jedenfalls schon recht interessant.

                Wieso? Weil die interne Numerierung nicht so läuft, wie du denkst?

                Wo beweist dieser Code, dass überschriebene Filehandles nicht freigegeben und entfernt werden?

                Es wird eine Weile dauern, das Innenleben von PHP entsprechend zu untersuchen ;-)

                Das mach mal. Ich denke aber, Christian hat das bereits getan, ansonsten hätte er nicht einige relevante Erweiterungen zu PHP 5.3 beigesteuert.

                - Sven Rautenberg

                1. Hello,

                  Wo beweist dieser Code, dass überschriebene Filehandles nicht freigegeben und entfernt werden?

                  Wo beweist Christians und Dein Vortrag, dass es so ist?

                  Ich muss zugeben, es ist nicht leicht, den Quell-Code von PHP zu verstehen. Aber da ihr Euch so sicher seid, dass PHP Referenzen auf fremde Ressourcen ordentlich wieder aufräumt, wenn die Referenzvariable (das Handle) _überschrieben_ wird, solltet Ihr mir bitte die Stelle im Code benennen.

                  Das würde mich dann enorm beruhigen.

                  Alleine konnte ich sie bisher nicht finden. Ich weiß noch zu wenig über den Aufbau der Programmstruktur weiß und habe leider auch noch nie selber einen so komplexen Parser geschrieben. Das würde jetzt sicher helfen...

                  Vorstellbar ist es bei einer Interpretersprache durchaus, dass sie sich um die Rückgabe von Handles an das Filesystem oder die Datenbank selber kümmert (macht sie _zum_ _Ende_ eines Scriptes ja auch, das macht ein Assemblerprogramm aber auch), aber nach meinen bisherigen Erfahrungen (und was mir ausdrücklich eingebläut wurde, um meine Arbeit erledigen zu können) ist das nicht so.

                  Nun will ich es aber bitte auch genau wissen und da wäre es ganz riesig von Euch beiden, wenn Ihr dabei helft :-)

                  Ich möchte also keine wilden Versuche anstellen, die auch nur wieder Indizien für das Für oder Wider wären, sondern die Stelle im Code finden, die bei der Wiederbenutzung einer noch nicht zurückgegebenen Handle-Variablen die Rückgabe automatisch veranlasst.

                  Liebe Grüße aus dem schönen Oberharz

                  Tom vom Berg

                  --
                  Nur selber lernen macht schlau
                  http://bergpost.annerschbarrich.de
                  1. Mahlzeit Tom,

                    Ich muss zugeben, es ist nicht leicht, den Quell-Code von PHP zu verstehen.

                    Ohne Dir jetzt zu nahe treten zu wollen ... IIRC ist dies ein Forum, indem es im weitesten Sinne um HTML, darin verfassten Dokumente (Inter- und Intranet) sowie die damit zusammenhängenden Technologien (CSS, Javascript, serverseitige Sprachen wie PHP usw., Datenbanken) geht - immer unter dem Aspekt der Verwendung bei der Erstellung von HTML-Seiten. Der Themenbereich "PHP" innerhalb des Forums umfasst dann auch eher Probleme bei der Anwendung von PHP, ggf. der Installation und Konfiguration.

                    AFAIK geht es nicht um den Aufbau von PHP, dessen Quellcode, Optimierungen auf Systemebene oder wie man die Sprache besser machen oder weiterentwickeln kann - dazu ist vielleicht eher das entsprechende Wiki geeignet.

                    Aber da ihr Euch so sicher seid, dass PHP Referenzen auf fremde Ressourcen ordentlich wieder aufräumt, wenn die Referenzvariable (das Handle) _überschrieben_ wird, solltet Ihr mir bitte die Stelle im Code benennen.

                    Wieso? Das ist IMHO nicht Ziel bzw. Inhalt dieses Forums.

                    Das würde mich dann enorm beruhigen.

                    Dann wende Dich an die Entwickler von PHP.

                    Alleine konnte ich sie bisher nicht finden. Ich weiß noch zu wenig über den Aufbau der Programmstruktur weiß und habe leider auch noch nie selber einen so komplexen Parser geschrieben. Das würde jetzt sicher helfen...

                    Das mag sein. Es geht hier im Forum aber primär nicht um den Aufbau von PHP oder wie man einen so komplexen Parser schreibt - sondern um die Anwendung von PHP im Rahmen der Erstellung von dynamischen Websites.

                    Bitte versteh mich nicht falsch, es kann natürlich sein, dass sich hier ein oder zwei (oder vielleicht auch mehr) Experten herumtreiben, die den PHP-Quellcode auswendig herunterbeten können, an sämtlichen Versionen mitgearbeitet haben und sich bestens auskennen und gerne austauschen ... aber ich bin schlicht und ergreifend der Meinung, dass diese Diskussion doch über den Umfang dieses Forums hinausgeht und die Wahrscheinlichkeit, zu diesen hochspeziellen Themen kompetente Gesprächspartner zu finden, hier doch erheblich geringer ist als in den Foren/Wikis/Mailing-Listen, die sich tatsächlich mit der Entwicklung von PHP beschäftigen.

                    MfG,
                    EKKi

                    --
                    sh:( fo:| ch:? rl:( br:> n4:~ ie:% mo:} va:) de:] zu:) fl:{ ss:) ls:& js:|
                    1. Hello,

                      Wieso? Das ist IMHO nicht Ziel bzw. Inhalt dieses Forums.

                      Na, dann bitte ich um Entschuldigung.

                      Liebe Grüße aus dem schönen Oberharz

                      Tom vom Berg

                      --
                      Nur selber lernen macht schlau
                      http://bergpost.annerschbarrich.de
                2. Moi moin Sven,

                  Man darf der Speicherverwaltung durchaus vertrauen.

                  apache_child_terminate() Der Speicher, und das ist das tatsächlich eklige an PHP, wird nur intern freigeben. Er wird nicht wieder fürs OS befreit. Gerade bei CLI-Anwendungen ist mir das all die Jahre immer wieder aufgefallen.

                  Gruß aus Berlin!
                  eddi

                  --
                  (v0.0.3 - also ganz der alte ;)
            2. Hello Christian,

              soweit ich das durchschaue, wird die Rückgabe des Handles (bei fopen) durch

              zend_list_delete(stream->rsrc_id);

              veranlasst.

              Das müsste dann also immer aufgerufen werden, wenn ein Funktionsblock verlassen wird, in dem eine Ressource-Variable angelegt wurde, egal ob die ressource direkt zurückgegeben wurde oder nur aufgegeben wurde und wenn eine Ressource-Variable mit einer neuen Ressource überschrieben wird, was ja nur umständlich ginge, weshalb dann die internen Ressource-Variablen vermutlich auch hochzählen?

              Wenn aber das Auflösen der Ressourcehandle-Bindung erst später durch die Garbage Collection vorgenommen wird, kann dies für die Datensicherheit (flushen der Buffers) und den Speicherverbrauch sehr negativ sein.

              Solltest Du also irgendwann Zeit dazu finden, die passenden Stellen im PHP-Quellcode mal zu suchen und zu benennen, dann würde ich mich darüber freuen.

              Mich interessiert dabei, wann genau die Bindung zur Ressource aufgelöst wird.
              Bei den Image-Funktionen gibt es sehr viele Berichte darüber, dass das wohl nicht zeitnah klappt, wenn man es nicht dediziert selber veranlasst.

              @EKKi:
              Wie ist das zu verstehen, dass Du jetzt vorgibst, wer hier was zu posten hat? Habe ich 'was verpasst?

              Liebe Grüße aus dem schönen Oberharz

              Tom vom Berg

              --
              Nur selber lernen macht schlau
              http://bergpost.annerschbarrich.de
              1. Mahlzeit Tom,

                @EKKi:
                Wie ist das zu verstehen, dass Du jetzt vorgibst, wer hier was zu posten hat? Habe ich 'was verpasst?

                Soll ich jetzt bei jedem einzelnen Deiner künftigen Beiträge nachschauen, ob vielleicht noch ein Halbsatz für mich dabei ist?

                Ich habe nicht vorgegeben, wer hier was zu posten hat. Ich habe lediglich angemerkt, dass die Diskussion bzw. Nachfrage, an welcher Stelle im Quellcode von PHP welche Handles freigegeben werden oder auch nicht, meiner Meinung nach in ein Forum/Wiki/Mailing-Liste gehört, das/die sich mit der Entwicklung von PHP beschäftigt ... und nicht in ein Forum, das sich vornehmlich mit der Entwicklung von Websites (ggf. unter Zuhilfenahme von PHP - und zwar lediglich als Anwendung bzw. Tools oder Hilfsmittel!) beschäftigt.

                Ich habe meinen Beitrag deutlich als MEINUNG gekennzeichnet (werde das auch bei diesem tun) und im Beitrag selbst mehr als einmal kenntlich gemacht, dass es sich um meine persönliche Meinung handelt.

                Ich lasse mir von Dir hier keinen Strick in Richtung "Forumspolizei", "Bestimmer", "Meinungs-Unterdrücker" oder sonstwas drehen.

                Wenn Du weiterhin so provozierende Sticheleien in meine Richtung abschießt, hat sich die Sache für mich damit erledigt.

                MfG,
                EKKi

                --
                sh:( fo:| ch:? rl:( br:> n4:~ ie:% mo:} va:) de:] zu:) fl:{ ss:) ls:& js:|
                1. Hello,

                  na jedenfalls scheinst Du gar nicht zu wissen, warum ich genauer nachfrage.

                  PHP hat zwar seit irgendwann in der 4er-Version einen Benutzungszähler für Ressourcen und eine "garbage collection ähnlich JAVA", aber es gibt keine Aussage darüber, wann der Garbage Collector denn genau greift.

                  Da das aber das gesamte Programmverhalten beeinflussen kann, gebe ich mich nicht mit einem

                  "Du erzählst, im Hinblick auf PHP, an dieser Stelle ebenfalls Unsinn."

                  abspeisen. Auch Christians Erklärungen gehen in keiner Weise auf die tatsächliche Funktionsweise ein. Im Web sind Dutzende von Alarmrufen zu finden, in denen ein "Lost Handle" die Ursache war, und das neueren in PHP5-Versionen (nicht allerdings PHP 5.3, das hat wohl noch keiner im Produktiveinsatz).

                  Ich habe eine zeitlang nichts anderes zu tun gehabt, als PHP-Sxcripts auf derartige "Schlampigkeiten" zu untersuchen und die zu korrigieren. Und der Witz an der Sache ist, dass die einschläfernden  Programme nach der Behandlung plötzlich keine Probleme mehr gemacht haben.

                  Es ist äußerst relevant, wann und wodurch die Bindung an die Ressource tatsächlöich ordentlich gelöst wird. Es hat Einfluss auf das Zurückschreiben Von Daten aus den Buffers in das File und auf das Locking. Wenn der Garbage Controller sich da auch nur eine Sekunde mehr Zeit lässt, als notwendig wäre, dann bekommt Du damit eine ganze Community zum Stehen!

                  Und diese Diskussion gehört durchaus in dieses Forum.

                  Liebe Grüße aus dem schönen Oberharz

                  Tom vom Berg

                  --
                  Nur selber lernen macht schlau
                  http://bergpost.annerschbarrich.de
                  1. Hallo Tom.

                    PHP hat zwar seit irgendwann in der 4er-Version einen Benutzungszähler für Ressourcen und eine "garbage collection ähnlich JAVA", aber es gibt keine Aussage darüber, wann der Garbage Collector denn genau greift.

                    »Thanks to the reference-counting system introduced with PHP 4's Zend Engine, a resource with no more references to it is detected automatically, and it is freed by the garbage collector. For this reason, it is rarely necessary to free the memory manually.«
                    [http://de3.php.net/manual/en/language.types.resource.php]

                    Das ist m.E. eine sehr genau Aussage darüber, wann der GC anspringt.

                    Servus,
                    Flo

                    1. Hello,

                      PHP hat zwar seit irgendwann in der 4er-Version einen Benutzungszähler für Ressourcen und eine "garbage collection ähnlich JAVA", aber es gibt keine Aussage darüber, wann der Garbage Collector denn genau greift.

                      »Thanks to the reference-counting system introduced with PHP 4's Zend Engine, a resource with no more references to it is detected automatically, and it is freed by the garbage collector. For this reason, it is rarely necessary to free the memory manually.«
                      [http://de3.php.net/manual/en/language.types.resource.php]

                      Das ist m.E. eine sehr genau Aussage darüber, wann der GC anspringt.

                      Nein, das ist Allgemein-Blah-Blah. Es sagt eben nichts aus darüber, wann der Garbage Collector anspringt. An anderern Stellen im Netz kann man sehr wohl nachlesen, dass er das nicht zeitnah tut, sondern manchmal mit erheblicher Verzögerung - wie bei JAVA.

                      Wenn ein Überschreiben der letzten Ressource-Variable, die bereits auf ein Ressource-Handle verweist, die unverzügliche ordnungsgemäße Rückgabe des Ressource-Handles zur Folge hätte, würde man ja keinen Garbage Collector mehr benötigen.

                      Da ich die gegenteiligen Aussagen nicht überprüfen kann, ohne in den Quellcode zu schauen, werde ich mich da also durchbeißen müssen.

                      Ich weiß nur, dass ich nicht eine zeitlang (bis die Firma verkauft wurde) damit beauftragt worden wäre, genau die "das braucht man nicht mehr"-Stellen zu finden und wieder klassisch zu lösen, wenn es nicht nützlich gewesen wäre. Die waren da echt geizig und hätten mir dann gewiss kein Geld bezahlt dafür...

                      Wie heißt das Modul, dass das "reference-counting" vornimmt? Muss ja irgendwie zu finden sein und dann zumindest auch so ungefähr zu verstehen, was da wann abläuft.

                      Liebe Grüße aus dem schönen Oberharz

                      Tom vom Berg

                      --
                      Nur selber lernen macht schlau
                      http://bergpost.annerschbarrich.de
                      1. Hallo,

                        Nein, das ist Allgemein-Blah-Blah.

                        Das ist tatsächlich so ein Problem von PHP. Die Dokumentation zurate zu ziehen, ist, wenn man eben nicht mal zwei drei Zeilen mit Datenbankverbindung dahinwurschtelt, ab einem gewissen Punkt ungenau. Ab einem gewissen Punkt muss man dann auch leider feststellen, dass nicht mehr ungenau ist sondern in Teilen sogar falsch. Das belege ich mal lieber gleich mit einem Beispiel:

                        $ PHPRC=/home/eddi/Desktop/ strace -o st /home/eddi/bin/php -i  
                        $ grep -e open st.txt
                        

                        open("/etc/ld.so.cache", O_RDONLY)      = 3
                        open("/lib/libcrypt.so.1", O_RDONLY)    = 3
                        open("/lib/libresolv.so.2", O_RDONLY)   = 3
                        open("/lib/libm.so.6", O_RDONLY)        = 3
                        open("/lib/libnsl.so.1", O_RDONLY)      = 3
                        open("/usr/lib/libxml2.so.2", O_RDONLY) = 3
                        open("/lib/libdl.so.2", O_RDONLY)       = 3
                        open("/lib/libz.so.1", O_RDONLY)        = 3
                        open("/lib/libpthread.so.0", O_RDONLY)  = 3
                        open("/lib/libc.so.6", O_RDONLY)        = 3
                        open("/usr/lib64/locale/locale-archive", O_RDONLY) = 3
                        open("/etc/localtime", O_RDONLY)        = 3
                        open("/home/eddi/Desktop/php-cli.ini", O_RDONLY) = -1 ENOENT (No such file or directory)
                        open("/home/eddi/bin/php-cli.ini", O_RDONLY) = -1 ENOENT (No such file or directory)
                        open("/home/eddi/conf/php-cli.ini", O_RDONLY) = 3

                        Laut Dokusuppe unter The configuration file sollte ein CLI im zur Compilierungszeit angegebenem Konfigurationsverzeichnis, im aktuelle Arbeitsverzeichnis und mittels Umgebungsfariable übergebenem Verzeichnis suchen. Stattdessen berücksichtigt es (Gott sei dank!) das Arbeitsverzeichnis nicht (mehr), auch wenn damals mein bug report Pauken und Trompeten abgeschmettert wurde. Darüber hinaus sucht es auch im Verzeichnis des Binärs nach seiner ini. Ganz anders verhält es sich wiederum beim Apache-Modul. Das sucht darüber hinaus auch noch im Wurzelverzeichnis nach einer ini. Im gesamten Manual findet sich keine brauchbare Beschreibung über das tatsächliche Verhalten PHPs im Bezug auf die Konfigurationsoption --with-config-file-scan-dir. Dies aber sollte in der oben genannten Dokumentationsseite jedenfalls zu finden sein. Man findet es nur durch Lesen der Sourcen heraus.

                        De facto kümmern sich die Devs nicht die Bohne um die Dokumentation. Es ist also mehr als verständlich, dass Tom hier Belege erfragt.

                        Da ich die gegenteiligen Aussagen nicht überprüfen kann, ohne in den Quellcode zu schauen, werde ich mich da also durchbeißen müssen.

                        Beiß die Zähne ganz fest zusammen. Dieser Ko - äh - Code ist quasi seine eigene Programmiersprach - alles voller Macros. Und, man merk alsbald, dass dort zu viele Leute nicht wissen, was der andere gerade gecodet hat.

                        Gruß aus Berlin!
                        eddi

                        --
                        (v0.0.3 - also ganz der alte ;)
                        1. Hello Eddi,

                          De facto kümmern sich die Devs nicht die Bohne um die Dokumentation. Es ist also mehr als verständlich, dass Tom hier Belege erfragt.

                          Da ich die gegenteiligen Aussagen nicht überprüfen kann, ohne in den Quellcode zu schauen, werde ich mich da also durchbeißen müssen.

                          Beiß die Zähne ganz fest zusammen. Dieser Ko - äh - Code ist quasi seine eigene Programmiersprach - alles voller Macros. Und, man merk alsbald, dass dort zu viele Leute nicht wissen, was der andere gerade gecodet hat.

                          So einfache Sachen, wie z.B. der Ablauf bei der mail()-Funktion usw., das kann ich ja schon finden, lesen und verstehen. Das ist mehr oder weniger nur C.

                          Aber alles, was nun direkt in der Schicht des Parsers liegt, also z.B. wie eine Variable angelegt und verwaltet wird, da fehlt mir doch noch etwas das Verständnis, wie man diese Stellen überhaupt findet. Gibt es dazu irgendwo eine umfangreichere Doku möglichst mit Grafiken u.ä.?

                          Vielleicht sollte ich mich generell mal mit Parser-Bau beschäftigen?
                          Hat jemand gut Einsteigertipps dafür?

                          Liebe Grüße aus dem schönen Oberharz

                          Tom vom Berg

                          --
                          Nur selber lernen macht schlau
                          http://bergpost.annerschbarrich.de
              2. Hallo,

                also, mal ein kleiner Exkurs zum Thema "Ressourcen in PHP - wie funktionieren die?":

                (Disclaimer: Ich betrachte hier PHP 5.3, PHP 5.2 ist aber bis auf den zykluserkennenden GC für die für dieses Posting relevante Aspekte identisch im Verhalten.)

                (Disclaimer 2: Ein besserer Titel für dieses Posting wäre wohl gewesen: Mehr über die Interna von PHP, als das gesammelte SELFHTML-Forum je wissen wollte.)

                (Disclaimer 3: Nur weiterlesen, wenn man an sowas wirklich interessiert ist.)

                Variablen in PHP

                Zuerst einmal sollten wir uns ansehen, wie PHP Variablen intern (in C) speichert. Dazu gibt es eine Struktur "zval", die sieht so aus:

                zend.h, ~ Zeile 328:

                struct _zval_struct {
                	/* Variable information */
                	zvalue_value value;		/* value */
                	zend_uint refcount__gc;
                	zend_uchar type;	/* active type */
                	zend_uchar is_ref__gc;
                };
                

                Die einzelnen Einträge:

                - value: Der "Wert" der Variablen (siehe unten)  - refcount__gc: Wie oft die Speicherstruktur der Variblen referenziert                  wird (siehe unten zu "Referenzen")  - type: Der Typ der Variable  - is_ref__gc: Ob die Variable eine richtige Referenz ist (siehe unten)

                Betrachten wir erstmal nur die wichtigsten Einträge, value und type. type gibt an, welchen Typ eine Variable hat. Dafür sind in PHP einige Konstanten definiert, die den Typ definieren:

                zend.h, ~ Zeile 518:

                #define IS_NULL         0
                #define IS_LONG         1
                #define IS_DOUBLE       2
                #define IS_BOOL         3
                #define IS_ARRAY        4
                #define IS_OBJECT       5
                #define IS_STRING       6
                #define IS_RESOURCE     7
                

                Es gibt ferner noch einige weitere Typen, die für interne Optimierungszwecke vorhanden sind:

                #define IS_CONSTANT     8
                #define IS_CONSTANT_ARRAY    9
                

                Sowie einige Konstanten, die per Bitmaske zum Typ hinzuaddiert werden können, die keinerlei Relevanz für den eigentlichen Datentyp haben, aber für andere Dinge gut sind (wieder Interna der Engine):

                #define IS_CONSTANT_TYPE_MASK   0x0f
                #define IS_CONSTANT_UNQUALIFIED 0x10
                #define IS_CONSTANT_INDEX       0x80
                #define IS_LEXICAL_VAR          0x20
                #define IS_LEXICAL_REF          0x40
                

                Wir ignorieren mal die erweiterten Dinge (alles > 7), die sind für die Diskussion nicht relevant, ich hab sie nur der Vollständigkeit halber angeführt. Die Basis-Typen sind relativ klar:

                Konstante      PHP-Datentyp  ---------------------------------  IS_NULL        null  IS_LONG        int  IS_DOUBLE      float  IS_BOOL        boolean  IS_ARRAY       array  IS_OBJECT      object  IS_STRING      string  IS_RESOURCE    resource

                [Anm.: In PHP 6 kommt natürlich noch IS_UNICODE für den unicode-Datentyp dazu.]

                Nun betrachten wir das Element value der Datenstruktur. Das ist vom Typ zvalue_value - und das ist eine Union:

                zend.h, ~ Zeile 317:

                typedef union _zvalue_value {
                	long lval;					/* long value */
                	double dval;				/* double value */
                	struct {
                		char *val;
                		int len;
                	} str;
                	HashTable *ht;				/* hash table value */
                	zend_object_value obj;
                } zvalue_value;
                

                Diese Union enthält folgende Elemente - je nach Datentyp:

                Datentyp  relevantes Element   -------------------------------   null      keines   int       lval (enthält den Integer-Wert direkt)   float     dval (enthält den Double-Wert direkt)   boolean   lval (ist entweder 0 oder 1)   array     ht   (HashTable ist eine C-Struktur mit der PHP Arrays                   abbildet, ich gehe hier nicht näher darauf ein)   object    obj  (zend_object_value ist ein bisschen komplizierter, im                   Endeffekt ist das wichtigste daran aber eine Zahl)   string    str  (in str.val wird der String als 0-Terminierte Zeichenkette                   (8-bit) abgelegt, in len wird zusätzlich die Länge                   gespeichert, damit PHP binäre Daten behalten kann)   resource  lval (enthält eine Zahl, die mit der Ressource zu tun hat                   und bei var_dump angezeigt wird)

                Speichermodell von Ressourcen

                Nun, wie wir hier sehen, werden Ressourcen als Zahlen gespeichert - wo sind aber die eigentlichen Daten der Ressource?

                Nunja, das ist etwas komplizierter. Es gibt in PHP eine Struktur, die nennt sich executor_globals (Typ ist definiert in zend_globals.h, ~ Zeile 164, sehr lang) - und dieses enthält zwei Einträge:

                struct _zend_executor_globals {
                // ...
                	HashTable regular_list;
                	HashTable persistent_list;
                // ...
                };
                

                Wir erinnern uns: HashTable ist PHPs interne Datenstruktur, um Arrays zu speichern. Sie kann alles, was normale Arrays in PHP auch können. Hier wird sie verwendet, um numerisch indizierte Daten zu speichern, die Nummer ist gerade die Nummer der Ressource. Der Unterschied zwischen regular_list und persistent_list hat nur zu tun mit den Funktionen, die persistente Verbindungen zu einer Datenbank aufbauen können, mysql_pconnect und so weiter. Die ignorieren wir hier mal und betrachten normale Ressourcen, wie die meisten es sind (File-Handles, Datenbank-Resultsets [1], etc.) und vor allem die sind, die uns interessieren. Die werden in dem Element regular_list gespeichert.

                Was für einen Typ haben denn die Elemente, die in dieser HashTable gespeichert werden (das sieht man so einem Ding nicht an - bei normalen PHP-Arrays sind die Elemente wieder zval-Strukturen bzw. genauer gesagt Zeiger auf diese)?

                zend_list.h, ~ Zeile 33:

                typedef struct _zend_rsrc_list_entry {
                	void *ptr;
                	int type;
                	int refcount;
                } zend_rsrc_list_entry;
                

                Betrachten wir die Elemente dieser Struktur:

                ptr - Ein beliebiger Zeiger auf irgend etwas. Dies ist spezifisch für          die Erweiterung die die Ressource erstellt hat, es könnte z.B.          irgend eine MySQL-interne Struktur sein oder irgend etwas          ähnliches.    type - Der Typ der Ressource - damit wird verhindert, dass man File-           Handles an Datenbankfunktionen übergeben kann.    refcount - Wie oft diese konkrete Ressource referenziert wurde.

                Betrachten wir zuerst Typen von Ressourcen: Jede Erweiterung, die eigene Ressourcen benutzen möchte, muss zuerst einen Ressourcen-Typ bei PHP registrieren, dies geht über die Funktion zend_register_list_destructors. Der übergibt man eine Desktruktor-Funktion [2] und eine interne Kennung von welcher Erweiterung die Ressource registriert wurde. Die Desktruktor-Funktion ist eine Funktion die man bereit stellen muss, die sich darum kümmert, dass eine Ressource ordnungsgemäß aufgeräumt wird. Die wird aufgerufen, sobald eine Ressource freigegeben wird. zend_register_list_destructors gibt der Erweiterung dann den zugewiesenen Typ zurück - das war ja eine Zahl. Der Typ kann dann in der obigen Struktur als Mitglied type gespeichert werden.

                Anlegen von Ressourcen (veranschaulicht)

                Stellen wir uns nun vor, eine Erweiterung möchte in PHP eine Ressource in einer Variable speichern. Was macht sie dann?

                Folgende Dinge seien gegeben:

                * Der Typ der Ressource ist in der C-Variable le_example_resource_type    gespeichert.  * zval *myvar zeigt bereits auf einen gültigen Speicherbereich, der eine    frischinitialisierte zval-Struktur enthält.  * Die interne Struktur, zu der ich eine Ressource anlegen will, liege in    der Variable my_type *my_struct.

                Die C-Erweiterung ruft nun folgendes auf:

                ret = zend_register_resource (myvar, my_struct, le_example_resource_type);
                if (ret == FAILURE) {
                  // Fehlerbehandlung
                }
                

                Was macht nun ihrerseits zend_register_resource? Sie ruft zend_list_insert auf und falls das erfolgreich war wird die ID der neu zugewiesenen Ressource in der zval-Struktur abgelegt.

                Was macht zend_list_insert? Der Prototyp ist so definiert:

                int zend_list_insert(void *ptr, int type);

                Die macht folgendes:

                1. Eine neue Struktur des Types _zend_rsrc_list_entry wird angelegt,     mit den folgenden Feldern:

                	le.ptr=ptr;
                	le.type=type;
                	le.refcount=1;
                

                2. Die Struktur wird intern in den HashTable regular_list der     executor_globals-Struktur hinzugefügt, analog zu array_push().

                3. Der frisch erstellte Index wird zurückgegeben.

                Der Index wird dann wie bereits erwähnt von zend_register_resource der zval-Struktur als value.lval zugewiesen.

                Kopien auf Ressourcen

                Nun betrachten wir ausschließlich* erst einmal vollwertige Kopien von Ressourcen, d.h. die Frage, was denn genau passiert, wenn ich folgendes mache:

                $ressource_kopie = $ressource;

                (Hinweis: Ich ignoriere copy-on-write-Semantiken mal, denn es gibt wirklich Situationen, in der in der PHP-Engine eine echte Kopie auch ausgeführt wird.)

                Wenn die obige Zeile ausgeführt wird, wird der Inhalt der Speicherstruktur der alten Variable ($ressource) in die Speicherstruktur der neuen Variable ($ressource_kopie) kopiert und dann über einige Umwege die Funktion _zval_copy_ctor_func auf die Speicherstruktur der neuen Variable ausgeführt. Die macht folgendes im Falle einer Ressourcen (zvalue zeigt auf die Speicherstruktur der neuen Variable):

                zend_variables.c, ~ Zeile 110: zend_list_addref(zvalue->value.lval);

                Wir erinnern uns: zvalue->value.lval ist die numerische Id der Ressource. Nun betrachten wir was zend_list_addref macht.

                zend_list_addref nutzt die internen Funktionen für HashTables, die PHP zur Verfügung stellt, um die Ressourcenstruktur zu finden, die zu dieser numerischen Id gehört. Sobald diese gefunden wurde, wird der Eintrag refcount inkrementiert:

                zend_list.c, ~ Zeile 87: le->refcount++;

                Je mehr "Kopien" von der Ressource herumfliegen, desto höher wird die Zahl. Die eigentliche Ressource wird dagegen nicht kopiert, die Id ist daher eine Art Referenz.

                Ausflug: Referenzen auf Variablen

                PHP unterstützt allerdings auch noch ein weiteres Konzept: Referenzen. Man kann nämlich eine Variable zu einer Referenz einer anderen Variable machen - wenn dann eine von beiden geändert wird, werden alle Referenzen auch geändert.

                Intern geschieht dies indem auf die gleiche C-Struktur gezeigt wird. Allerdings reicht dies noch nicht ganz: Man muss nämlich noch Buch führen, wie oft auf die Speicherstruktur tatsächlich gezeigt wird, damit man weiß, wann der Speicher freigegeben werden kann.

                Also gibt es in jeder Speicherstruktur den Eintrag refcount__gc und is_ref__gc. is_ref__gc ist entweder 0 (keine Referenz) oder 1 (Referenz) und refcount__gc gibt an, wie oft die Variable referenziert wurde.

                Beispiel (für einfache Variablen):

                $a = 5; // refcount__gc($a) == 1
                                       // is_ref__gc($a) == 0
                $b =& $a; // $a und $b zeigen auf die gleiche C-Speicherstruktur
                          // refcount__gc($a) == 2
                          // is_ref__gc($a) == 1
                $a = 3;  // $b wird auch geändert
                $c =& $b; // $c zeigt auf gleiche Speicherstruktur wir $a und %b,
                          // refcount__gc($a) == 3
                          // is_ref__gc($a) == 1
                // etc.
                

                copy-on-write-Semantiken

                Naja, und weil das ganze so schön war, setzen wir nun nochmal eins drauf. Aus Performancegründen kopiert PHP nämlich Variablen nur dann, wenn tatsächlich irgend etwas geändert wird. Beispiel:

                $a = 'sehr langer string ...'; // refcount__gc($a) == 1
                                                              // is_ref__gc($a) == 0
                $b = $a; // $b zeigt nun auf die gleiche Speicherstelle wie $a
                         // refcount__gc($a) == 2
                         // is_ref__gc($a) == 0
                $c = $b; // $c zeigt nun auf $a bzw. $b
                         // refcount__gc($a) == 3
                         // is_ref__gc($a) == 0
                $a = 'neuer string'; // bei $b / $c wird der refcount__gc dekrementiert
                                     // und bei $a wird eine neue Variablenstruktur
                                     // angelegt, so dass
                                     // refcount_gc($a) == 1, is_ref__gc($a) == 0
                                     // refcount_gc($b) == 2, is_ref__gc($b) == 0
                // usw.
                

                Man erhält also eine Art Pseudo-Referenzen, bei denen jedoch beim Zuweisen die zugewiesene Variable "separiert" wird - d.h. die geänderte Variable erhält eine neue Struktur während der Rest der Variablen, die auf die gleiche Struktur gezeigt haben, unverändert geblieben sind - mit Ausnahme dass der refcount__gc kleiner geworden ist.

                Das ganze gewinnt dann natürlich noch ein paar Nettigkeiten hinzu: Da diese beiden Arten von Referenzen inkompatibel miteinander sind (is_ref__gc kann ja nicht gleichzeitig 0 oder 1 sein), wird das Zusammenspiel gerne mal ziemlich kompliziert:

                function test1 ($parameter) { return; }
                function test2 (&$referenz_parameter) { return; }
                
                $a = 5;
                $b =& $a;
                $c = $b; // Hier muss nun eine tatsächliche Kopie angelegt werden, da wir
                         // ja nicht wollen, dass $c mit in der Referenz enthalten ist
                         // $c soll stattdessen
                test1 ($b); // Hier muss auch eine Kopie angelegt werden, weil wir ja auch
                            // nicht wollen, dass die Funktion intern durch Änderung der
                            // Parametervariable die übergebene Variable ändert
                            // Dies ist übrigens der Hauptgrund, warum Referenzen in PHP
                            // in Wirklichkeit sogar langsamer sind als "Kopien", weil
                            // "Kopien" eben keine Kopien sind, Referenzen bei Readonly-
                            // Funktionsparametern aber immer kopiert werden müssen
                            // (Ja, das ist irgendwie pervers)
                test2 ($b); // Hier kann solange das als Parameter übergeben wird der
                            // refcount__gc einfach um 1 erhöht werden, es muss also keine
                            // Kopie gemacht werden.
                

                Noch lustiger wird's dann natürlich, wenn man den Inhalt einer Variable, die bereits eine Referenz oder eine Pseudo-Referenz ist, an eine andere Variable zuweist, die eine richtige Referenz wird. Dann drehen sich einem die Gehirnwindungen um, welche Variable jetzt nun wie eine neue Speicherstruktur bekommt und welche refcount__gc-Werte wie gesetzt werden. Vor allem wenn man dann in C mit Zeigern auf Zeigern arbeiten muss. ;-)

                Wie auch immer, das wichtigste dieses Abschnitts ist hoffe ich hängen geblieben.

                copy-on-write in Bezug auf Ressourcen

                Nun haben wir folgendes gesehen: Ressourcen sind einerseits selbst nur Referenzen und die Ressource-Struktur hat einen Eintrag refcount, der angibt, wie viele "Kopien" der Ressource in verschiedenen (!) Variablenstrukturen umherschwirren. Außerdem kann die gleiche Variablenstruktur von mehreren Variablen geteilt werden und hat damit selbst noch einen Eintrag refcount__gc, der die Kopien der Variablenstruktur zählt.

                Es ist also möglich, folgende Speichersituation zu konstruieren:

                Variable               C-Struktur                           Ressource

                +-------------------+                +---------------+   $a   ------------->| refcount__gc == 2 |   +------> 42: | refcount == 2 |   $b   ------------->| value.lval == 42--|---+            | type == 54    |                      | ...               |   |            | ptr == ...    |                      +-------------------+   |            +---------------+                                              |                      +-------------------+   |            +---------------+   $c   ------------->| refcount__gc == 1 |   |  +---> 36: | refcount == 1 |                      | value.lval == 42--|---+  |         | type == 56    |                      | ...               |      |         | ptr == ...    |                      +-------------------+      |         +---------------+                                                 |                      +-------------------+      |   $d   ------------->| refcount__gc == 1 |      |                      | value.lval == 36--|------+                      | ...               |                      +-------------------+

                Schön, was? ;-)

                Vernichten von Variablen, Garbage Collection 5.2 Edition

                Nun, was passiert nun mit Variablen, die aus dem Funktionsscope fallen? Beispiel:

                function foo () {
                  $a = 5;
                }
                

                Was passiert mit $a am Ende der Funktion? Nun, da müssen wir in der Funktion zend_call_function nachsehen, was nach einem Funktionaufruf geschieht:

                zend_execute_API.c, ~ Zeile 939 [3]: zend_hash_destroy(EG(active_symbol_table));

                (EG(v) ist ein Macro, das zu executor_globals.v expandiert oder zu einem komplizierteren Ausdruck wenn Threads verwendet werden.)

                zend_hash_destroy schaut im HashTable nach, welche Destrukturfunktion es aufrufen soll (die wird intern gespeichert) - und für EG(active_symbol_table) ist dies die Funktion zval_ptr_dtor.

                Was macht nun zval_ptr_dtor? Schauen wir nach:

                zend_execute_API.c, ~ Zeile 429: Z_DELREF_PP(zval_ptr);

                Z_DELREF_PP ist ein Makro, das refcount__gc herabsetzt (es hat seine Gründe warum das ein Makro ist, die ich hier jetzt nicht näher ausführen will).

                Was passiert nun als nächstes? (nächste Zeile)

                if (Z_REFCOUNT_PP(zval_ptr) == 0) {

                Also, wenn festgestellt wird, dass der Referenz-Zähler auf 0 angekommen ist, wird die Struktur nun nicht mehr benötigt. Dann wird im Endeffekt folgendes ausgeführt (mit ein paar Checks + kompliziertereren Dingen):

                zval_dtor(*zval_ptr);

                Schauen wir uns nun an, was zval_dtor() macht, wenn es sich um eine Ressource handelt:

                zend_variables.c, ~ Zeile 60: zend_list_delete(zvalue->value.lval);

                Was passiert nun in zend_list_delete?

                zend_list.c, ~ Zeile 57:

                		if (--le->refcount<=0) {
                			return zend_hash_index_del(&EG(regular_list), id);
                		} else {
                			return SUCCESS;
                		}
                

                Wir sehen hier also, dass der Eintrag refcount der Ressource dekrementiert wird. Wenn dieser 0 erreicht hat (if-Abfrage), dann wird die Funktion zend_hash_index_del aufgerufen - die dann den Ressourcen-Eintrag komplett aus der Liste entfernt. Diese ruft dann wiederum über einige indirekte Dinge den Destruktor der Ressource auf (der ganz am Anfang per zend_register_list_destructors registriert wurde!) - und wenn der richtig geschrieben wurde (was m.W. für alle Standard-PHP-Erweiterungen der Fall ist), dann gibt er alles frei, worauf die Ressource vorher gezeigt hat.

                Betrachten wir nun, was am Ende der folgenden Funktion geschieht:

                function foobar () {
                 $fp = fopen ('test.txt', 'r');
                }
                

                - Variable $fp gerät aus dem Scope -> refcount__gc der zugehörigen    Speicherstruktur wird dekrementiert.

                - refcount__gc erreicht 0 -> Variablenstruktur wird aufgeräumt per    zval_dtor.

                - zval_dtor für Ressourcen: Ruft zend_list_delete auf.

                - zend_list_delete dekrementiert den refcount der Ressource.

                - refcount der Ressource erreicht 0 -> Ressource-Destruktor wird    aufgerufen.

                - Ressource-Destruktor schließt (hier in diesem Fall) die Datei.    Unmittelbar.

                Damit werden Ressourcen immer automatisch am Ende einer Funktion freigegeben GENAU DANN WENN keine einzige Kopie/Referenz auf die ursprünglich durch diese Ressource angelegte Variable mehr existiert.

                q.e.d.

                Zusatz: Garbage Collection 5.3 Edition

                Nunja, und weil's so schön war, können wir kurz noch über die Verbesserung des Garbage-Collectors in PHP 5.3 reden. Der ändert das oben beschriebene Verhalten nämlich NICHT. Das bleibt von PHP 5.2 zu PHP 5.3 gleich.

                Allerdings kann der Garbage-Collector von PHP 5.3 etwas, was PHP 5.2 nicht konnte: Zyklische Referenzen auflösen. Machen wir mal ein Beispiel aus der OOP:

                class Node {
                  public $parent = null;
                  public $children = array ();
                
                  public function addChild (Node $n) {
                    // Jaja, hier sollte eigentlich noch überprüft werden, ob $n->parent
                    // null ist und dann reagiert werden, ich lasse das mal weg. ;-)
                    $n->parent = $this;
                    $this->children[] = $n;
                  }
                }
                
                $root = new Node;
                $root->addChild (new Node);
                unset ($root);
                

                Erst einmal: Was genau passiert hier? Das $n->parent = $this erzeugt eine "Referenz" auf das aktuelle Objekt (ich unterschlage hier mal sehr viele Details weil ich mit dem Posting fertig werden will ;-)). Das heißt, dass ich folgende logische Struktur habe:

                $root       |       |              +-----------------------------------------+       |              |                                         |       v              v                                         |   +----------------------+           +----------------------+  |   | $parent = null       |  +------->| $parent = -----------|--+   | $children = array (  |  |        | $children = array () |   |    0 =>  ------------|--+        +----------------------+   | )                    |   +----------------------+

                Wir sehen also: refcount__gc von $root ist 2 (oder der ->parent-Eintrag ist ne Kopie der Variablenstruktur und die interne Objekt-Id hat einen Objekt-refcount von 2, was aber hier für das Ergebnis irrelevant ist). Wenn man nun also mit unset ($root); die Variable explizit löscht (ans Ende der Funktion gelangen hat den gleichen Effekt), wird der refcount__gc um 1 dekrementiert. Der ist jetzt nur noch 1. Das ganze sieht dann so aus:

                +-----------------------------------------+                      |                                         |                      v                                         |   +----------------------+           +----------------------+  |   | $parent = null       |  +------->| $parent = -----------|--+   | $children = array (  |  |        | $children = array () |   |    0 =>  ------------|--+        +----------------------+   | )                    |   +----------------------+

                Die beiden Strukturen zeigen nun aufeinander - aber es gibt keine Möglichkeit, über simples Reference Counting die Dinge noch loszuwerden. Klar, am Ende des Requests sind die zwangsweise weg, weil PHP alle Variablen vernichtet, aber wenn man etwas längeres laufen hat oder etwas was dauernd zyklische Referenzen erzeugt und die zugehörigen Objekte (oder auch Arrays mit =&-Typ-Referenzen) wieder löscht ohne die Zyklen aufzubrechen, der hat sich ein Speicherleck gebaut - oftmals ein sehr großes.

                Daher kann der neue Garbage-Collector in PHP 5.3 zyklische Referenzen erkennen und beseitigen - und somit zusätzlich zum bisherigen Verhalten Probleme verhindern, die sonst aufgetreten wären.

                Abschluss

                Ich hoffe, ich habe hiermit darlegen können, dass mein voriges Posting den Tatsachen entsprach und dass PHP tatsächlich hinter Ressourcen herräumt, die man im Scope rumliegen lässt, sobald man ebendiesen verlässt.

                Ich hoffe ferner auch, dass Aussagen meinerseits zu den Interna von PHP nicht mehr nur deswegen abgetan werden, weil sie nicht in das bereits vorhandene, mehr oder weniger verzerrte Weltbild passen, sondern erst dann, wenn objektive (!) Indizien vorhanden sind, dass sie falsch sind. Nein, ich will kein Autoritätsargument à la "Ich hab's gesagt, also stimmt's." konstruieren - aber bei Experten auf einem gewissen Gebiet sollte IMHO doch gelten: "Ich hab's gesagt, also sollte man das genauer untersuchen, bevor man ihm doch widerspricht." Ich kann mich selbstverständlich auch irren, keine Frage, aber meine Erfahrung auf einem gewissen Gebiet (hier: PHP-Interna) sollte als sehr starkes Argument für den Wahrheitsgehalt der Aussage gelten, das erst mit anderen Argumenten aufgewogen werden muss. Ich hoffe, das kommt jetzt nicht zu arrogant herüber, es ist einfach nur eine praktische Überlegung: Wenn jeder Experte jedem gegenüber jede Kleinigkeit immer wieder von vorne rechtfertigen müsste, ohne dass der andere ausreichend Anstrengungen unternimmt, dies vorab (!) selbst zu verstehen, dann stünde die Welt still.

                Fußnoten

                [1] Die Resultsets von persistenten Verbindungen sind selbst nicht persistent.

                [2] Eigentlich sind es zwei Destruktor-Funktionen: Je eine für persistente und normale Ressourcen.

                [3] Ok, in Wirklichkeit ist's etwas komplizierter, da HashTables aus Performancegründen gecached werden (siehe else-Zweig an der Stelle), allerdings wird im else-Zweig dennoch zend_hash_clean() aufgerufen, was den Hash komplett leert und damit auch die Destruktoren aufruft.

                Viele Grüße, Christian

                PS: Für alle, die sich wundern: Ja, ich habe ganz schamlos meine Privilegien auf dem Server ausgenutzt, um das Limit für Postinggrößen temporär zu erhöhen, damit ich das hier nicht herunterbrechen musste. ;-)

                --
                Mein "Weblog" [RSS] Using XSLT to create JSON output (Saxon-B 9.0 for Java) »I don't believe you can call yourself a web developer until you've built an app that uses hyperlinks for deletion and have all your data deleted by a search bot.«             -- Kommentar bei TDWTF
                1. Hello Christian,

                  also, mal ein kleiner Exkurs zum Thema "Ressourcen in PHP - wie funktionieren die?":

                  jetzt wird's spannend. *freu*

                  (Disclaimer: Ich betrachte hier PHP 5.3, PHP 5.2 ist aber bis auf den zykluserkennenden GC für die für dieses Posting relevante Aspekte identisch im Verhalten.)

                  Ack

                  (Disclaimer 2: Ein besserer Titel für dieses Posting wäre wohl gewesen: Mehr über die Interna von PHP, als das gesammelte SELFHTML-Forum je wissen wollte.)

                  *schmunzel*

                  (Disclaimer 3: Nur weiterlesen, wenn man an sowas wirklich interessiert ist.)

                  *rotfl*

                  Also "zval" habe ich schon begriffen ;-)
                  (Ich poste dann ca. Ende nächster Woche wieder)

                  Dies ist also nur der Vorschuss-Dank.

                  Liebe Grüße aus dem schönen Oberharz

                  Tom vom Berg

                  --
                  Nur selber lernen macht schlau
                  http://bergpost.annerschbarrich.de
                2. Hello,

                  etlichen Spuren bin ich nun schon gefolgt.

                  Mir ist auch trotz deiner ausführlichen Ausführungen leider immer noch unbekannt, wo genau die Bindung des Variablennamens an eine Instanz der _zval_struct stattfindet.

                  Hoffentlich habe ich es jetzt nicht in deiner Beschreibung überlesen. Dann bitte ich um Verzeihung :-)

                  Liebe Grüße aus dem schönen Oberharz

                  Tom vom Berg

                  --
                  Nur selber lernen macht schlau
                  http://bergpost.annerschbarrich.de
                  1. echo $begrüßung;

                    Mir ist auch trotz deiner ausführlichen Ausführungen leider immer noch unbekannt, wo genau die Bindung des Variablennamens an eine Instanz der _zval_struct stattfindet.

                    Was willst du mit dem Namen? Das Wesentliche ist doch die ZVAL-Struktur. Vielleicht zeigt ein Variablenname (oder auch mehrere) auf sie, vielleicht ein Array-Element (oder auch mehrere), vielleicht eine Objekteigenschaft (oder auch mehrere). Vielleicht auch nicht, wenn sie (Zwischen?)Ergebnis [*] eines Ausdrucks oder ein Funktionsergebnis ist, was grad an keine Variable gebunden ist. Soweit ich weiß, muss es Strukturen geben, die für den globalen oder einen lokalen Gültigkeitsbereich für die Auflistung der Variablennamen zuständig sind.

                    [*] Ob für die zwischenergebnisse von Ausdrücken ZVAL-Container angelegt werden, weiß ich nicht. Vorstellen kann ich mir aber, das das so gemacht wird.

                    echo "$verabschiedung $name";

                    1. Hello,

                      Mir ist auch trotz deiner ausführlichen Ausführungen leider immer noch unbekannt, wo genau die Bindung des Variablennamens an eine Instanz der _zval_struct stattfindet.

                      Was willst du mit dem Namen?

                      Ich will wissen, wie geprüft wird, ob er schon verwendet wurde im selben Scope.

                      (Außerdem denke ich, dass man daraus auch noch andere Dinge lernen könnte, aber das hat nichts mit der eigentlichen Fragestellung zu tun)

                      Das Wesentliche ist doch die ZVAL-Struktur.

                      Das ist mMn schon einen Schritt zu spät.

                      Vielleicht zeigt ein Variablenname (oder auch mehrere) auf sie, vielleicht ein Array-Element (oder auch mehrere), vielleicht eine Objekteigenschaft (oder auch mehrere).

                      Es darf aber ein Variablenname (aus demselben Scope) nicht mehrfach darauf zeigen. Das wird ja sicherlich auch irgendwo überprüft. Jeder Variablenname muss innerhalb seines Scopes einmalig sein.

                      Liebe Grüße aus dem schönen Oberharz

                      Tom vom Berg

                      --
                      Nur selber lernen macht schlau
                      http://bergpost.annerschbarrich.de
                      1. echo $begrüßung;

                        » Das Wesentliche ist doch die ZVAL-Struktur.
                        Das ist mMn schon einen Schritt zu spät.

                        Zuerst gibt es den ZVAL-Container, in dem der Wert lagert. Was darauf zeigt sind nachfolgende Schritte, denn erst wird ein Wert erzeugt, dann wird er einer Variablen zugewiesen oder auch nicht. Beachte: ZVAL wie Value und nicht ZVAR wie Variable.

                        » Vielleicht zeigt ein Variablenname (oder auch mehrere) auf sie, vielleicht ein Array-Element (oder auch mehrere), vielleicht eine Objekteigenschaft (oder auch mehrere).
                        Es darf aber ein Variablenname (aus demselben Scope) nicht mehrfach darauf zeigen. Das wird ja sicherlich auch irgendwo überprüft. Jeder Variablenname muss innerhalb seines Scopes einmalig sein.

                        Irrtum. Durch PHPs Verhalten, eine echte Kopie erst dann anzulegen, wenn die Werte auseinanderlaufen, können durchaus mehrere Variablennamen auf den gleichen ZVAL-Container zeigen. Ganz abgesehen von Referenzen.

                        Schau dir auch mal den Artikel References Explained (by Derick Rethans) an. Ein Link dorthin "versteckt" sich im Kapitel zur Funktion debug_zval_dump().

                        echo "$verabschiedung $name";

                        1. Hello,

                          Irrtum. Durch PHPs Verhalten, eine echte Kopie erst dann anzulegen, wenn die Werte auseinanderlaufen, können durchaus mehrere Variablennamen auf den gleichen ZVAL-Container zeigen. Ganz abgesehen von Referenzen.

                          Nee, nee. Du denkst jetzt in eine falsche Richtung. Das wollte ich gar nicht untersuchen (noch nicht). Ich wollte sehen, was genau dann passiert, wenn ein absoluter Variablenname (also ein Name innerhalb desselben Scopes) das zweite Mal benutzt wird, um ihn mit einem zval zu verknüpfen.

                          Das geschieht mMn nur dann, wenn die noch vorhandene Variable überschrieben wird.

                          Liebe Grüße aus dem schönen Oberharz

                          Tom vom Berg

                          --
                          Nur selber lernen macht schlau
                          http://bergpost.annerschbarrich.de
                          1. echo $begrüßung;

                            Ich wollte sehen, was genau dann passiert, wenn ein absoluter Variablenname (also ein Name innerhalb desselben Scopes) das zweite Mal benutzt wird, um ihn mit einem zval zu verknüpfen.

                            Anzunehmenderweise wird der refcount im ZVAL-Container eins runtergezählt und die Variable dazu gebracht auf einen anderen ZVAL-Container zu zeigen, dessen refcount hochgezählt wird.

                            Das geschieht mMn nur dann, wenn die noch vorhandene Variable überschrieben wird.

                            Eine Variable ist nach meinem Verständnis ein Eintrag in einer der Variablenlisten mit einem Verweis auf einen ZVAL-Container.

                            echo "$verabschiedung $name";

                            1. Hello,

                              Ich wollte sehen, was genau dann passiert, wenn ein absoluter Variablenname (also ein Name innerhalb desselben Scopes) das zweite Mal benutzt wird, um ihn mit einem zval zu verknüpfen.

                              Anzunehmenderweise wird der refcount im ZVAL-Container eins runtergezählt und die Variable dazu gebracht auf einen anderen ZVAL-Container zu zeigen, dessen refcount hochgezählt wird.

                              Das geschieht mMn nur dann, wenn die noch vorhandene Variable überschrieben wird.

                              Eine Variable ist nach meinem Verständnis ein Eintrag in einer der Variablenlisten mit einem Verweis auf einen ZVAL-Container.

                              Beides: genau! Aber ich möchte gerne die ungenaue Vorstellung gegen genaues Wissen tauschen.

                              Und da ist es dann entscheidend: Was geschieht genau, wenn der RefCount 0 wird? Wird dann SOFORT der Destruktor des Objektes aufgerufen, oder wird dies erst irgendwann beim Aufräumen gemacht?

                              Der Aufruf des Destruktors müsste stattfinden, _direkt_ _nachdem_ das neue Paar "Name -> zval-Container" erzeugt worden ist.

                              Liebe Grüße aus dem schönen Oberharz

                              Tom vom Berg

                              --
                              Nur selber lernen macht schlau
                              http://bergpost.annerschbarrich.de
                              1. Hallo,

                                Und da ist es dann entscheidend: Was geschieht genau, wenn der RefCount 0 wird? Wird dann SOFORT der Destruktor des Objektes aufgerufen,

                                Ja. Das hatte ich doch in der Codestelle gezeigt: zval_ptr_dtor (zend_execute_API.c) setzt den Refcount eines ZVALs herunter, wenn der 0 erreicht hat, wird der Destruktor aufgerufen (zval_dtor_func, zend_variables.c) und das ruft dann die entsprechenden Destruktoren auf für die einzelnen Dinge, z.B. für Ressourcen etc. Da wird nicht auf das Aufräumen gewartet.

                                Andere Sprachen machen sowas ähnliches teilweise, PHP nicht.

                                Viele Grüße,
                                Christian

                                --
                                Mein "Weblog" [RSS]
                                Using XSLT to create JSON output (Saxon-B 9.0 for Java)
                                »I don't believe you can call yourself a web developer until you've built an app that uses hyperlinks for deletion and have all your data deleted by a search bot.«
                                            -- Kommentar bei TDWTF
                  2. Hallo,

                    Mir ist auch trotz deiner ausführlichen Ausführungen leider immer noch unbekannt, wo genau die Bindung des Variablennamens an eine Instanz der _zval_struct stattfindet.

                    executor_globals.active_symbol_table ist ein HashTable (siehe zend_globals.h, ~ Zeile 182), der alle aktuell gültigen Variablen enthält, d.h. dort sind die Keys die Namen der Variablen und die Werte die zval-Zeiger.

                    (Es gibt noch einige Optimierungen, die in 5.3 den active_symbol_table oftmals überflüssig machen, das unterschlage ich hier aber mal - das hat im Endeffekt nur mit der Performance zu tun, mit nichts weiter.)

                    Viele Grüße,
                    Christian

                    --
                    Mein "Weblog" [RSS]
                    Using XSLT to create JSON output (Saxon-B 9.0 for Java)
                    »I don't believe you can call yourself a web developer until you've built an app that uses hyperlinks for deletion and have all your data deleted by a search bot.«
                                -- Kommentar bei TDWTF
                    1. Hallo nochmal,

                      (Es gibt noch einige Optimierungen, die in 5.3 den active_symbol_table oftmals überflüssig machen, das unterschlage ich hier aber mal - das hat im Endeffekt nur mit der Performance zu tun, mit nichts weiter.)

                      Nochmal Nachtrag: Ok, das war etwas undeutlich ausgedrückt: Die Optimierung gibt's schon eine ganze Weile (seit PHP 5 denke ich, bin mir da aber nicht sicher) - in PHP 5.3 gibt's aber eine zusätzliche Optimierung dass active_symbol_table nur dann genutzt wird, wenn die Optimierung nicht greifen kann (z.B. bei variablen Variablennamen etc.).

                      Das Optimierungskonzept an sich nennt sich bei PHP Compiled variables, die Änderung für PHP 5.3, die den active_symbol_table nicht mehr erzeugt hat, wenn alles über CVs abgebildet war, gab's hier.

                      Viele Grüße,
                      Christian

                      --
                      Mein "Weblog" [RSS]
                      Using XSLT to create JSON output (Saxon-B 9.0 for Java)
                      »I don't believe you can call yourself a web developer until you've built an app that uses hyperlinks for deletion and have all your data deleted by a search bot.«
                                  -- Kommentar bei TDWTF
                      1. Hello,

                        Nochmal Nachtrag: Ok, das war etwas undeutlich ausgedrückt: Die Optimierung gibt's schon eine ganze Weile (seit PHP 5 denke ich, bin mir da aber nicht sicher) - in PHP 5.3 gibt's aber eine zusätzliche Optimierung dass active_symbol_table nur dann genutzt wird, wenn die Optimierung nicht greifen kann (z.B. bei variablen Variablennamen etc.).

                        Ach Sch...., das gibt es ja auch noch.

                        Ich denke, dass ich die Woche nun doch brauchen werden, das alles nachzuvollziehen :-)

                        Jedenfalls nochmals Dank an Deine Adresse!

                        Liebe Grüße aus dem schönen Oberharz

                        Tom vom Berg

                        --
                        Nur selber lernen macht schlau
                        http://bergpost.annerschbarrich.de
                3. Hallo Christian,

                  Wenn jeder Experte *jedem* gegenüber *jede* Kleinigkeit immer wieder von vorne rechtfertigen müsste, ohne dass der andere ausreichend Anstrengungen unternimmt, dies vorab (!) selbst zu verstehen, dann stünde die Welt still.

                  Du bist nicht in einer Arena, Du bist in einem Forum und verkennst vollends die Möglichkeiten der Beschleunigung der Welt durch Vermittlung von Wissen, statt des elitären Hütens.

                  Gruß aus Berlin!
                  eddi

                  --
                  Ab einem gewissen Erkenntnisstand ist die Versuchung wohl zu groß, in diesem und seinen begleitenden Errungenschaften zu verharren.
                  Das nenne ich Aufblick zu den Stufen des Tempels von der geistigen Gosse aus!
                  1. Hallo Eddi,

                    Wenn jeder Experte *jedem* gegenüber *jede* Kleinigkeit immer wieder von vorne rechtfertigen müsste, ohne dass der andere ausreichend Anstrengungen unternimmt, dies vorab (!) selbst zu verstehen, dann stünde die Welt still.

                    Du bist nicht in einer Arena, Du bist in einem Forum und verkennst vollends die Möglichkeiten der Beschleunigung der Welt durch Vermittlung von Wissen, statt des elitären Hütens.

                    Du hast nur einen Teil des gesamten Abschnitts zitiert und damit meine Aussage komplett verfälscht. Mir geht es wirklich nicht darum, im Recht zu sein und mich mit anderen Leuten zu "messen".

                    Nur gibt es in meinen Augen einen gewaltigen Unterschied zwischen "Wissen vermitteln" und "alle Aussagen auf Adam und Eva zurückzuführen". Ich habe in meiner ersten Antwort auf Tom erklärt, warum man Result-Sets nicht freigeben muss: Nämlich dass sowas automatisch geschieht, sobald die Ressource aufhört zu existieren, z.B. weil die Variable aus dem Scope fällt oder mit etwas anderem überschrieben wird.

                    Nun hat Tom diese Begründung angezweifelt. Ich stelle ihm das nicht in Abrede. Ich stelle ihm auch nicht in Abrede, Nachfragen dazu zu stellen. Aber ich finde es nicht in Ordnung, wenn er dann weiterhin hier im Forum *nach* meinem Einspruch weiterhin das Gegenteil behauptet (er hat mehrfach "ich habe mal gelesen/gehört, dass ..." eingeworfen), ohne sich in ausreichendem Maße um eine vorige Recherche / Nachfrage gekümmert zu haben. Und wenn das zu Fehlinformationen führt, die hier im Forum verbreitet werden, die dann von anderen Leuten gelesen werden, dann kreide ich das an - und das wollte ich mit dem Absatz erreichen. Denn auch mir geht es hier um das Verbreiten von Wissen - und nichts ist dem Verbreiten von Wissen in meinen Augen hinderlicher als Fehlinformationen.

                    Ich hoffe, das macht die Intention meines letzten Absatzes klarer.

                    Viele Grüße,
                    Christian

                    --
                    Mein "Weblog" [RSS]
                    Using XSLT to create JSON output (Saxon-B 9.0 for Java)
                    »I don't believe you can call yourself a web developer until you've built an app that uses hyperlinks for deletion and have all your data deleted by a search bot.«
                                -- Kommentar bei TDWTF
                    1. Re:

                      ...

                      Wäre sonst dieser/Dein Tiefgang in die Materie auch für mich sonst hier zu lesen gewesen? Hätte ich mich darum überhaupt mal geschert? ;)

                      "Ein Teil von jener Kraft, Die stets das Böse will und stets das Gute schafft." von Goethe; Faust; Studierzimmer

                      Manches verbirgt sich unter einem Mantel, aber wird gesehen werden, wenn man es zulässt.

                      Gruß aus Berlin!
                      eddi

                      --
                      Ab einem gewissen Erkenntnisstand ist die Versuchung wohl zu groß, in diesem und seinen begleitenden Errungenschaften zu verharren.
                      Das nenne ich Aufblick zu den Stufen des Tempels von der geistigen Gosse aus!
                      1. Hallo Eddi,

                        Wäre sonst dieser/Dein Tiefgang in die Materie auch für mich sonst hier zu lesen gewesen?

                        Vielleicht, vielleicht auch nicht, keine Ahnung - gegen Nachfragen habe ich ja wie gesagt nichts und es hätte gut sein können dass ich auf eine simple Nachfrage durchaus auch sowas geschrieben hätte. Vielleicht auch nicht - jetzt werden wir's nie erfahren. Aber: Es ist halt eine Ausnahme, dass ich mal vier bis fünf Stunden Zeit zum Recherchieren und Posting-Schreiben finde. Ich hatte zu dem Zeitpunkt zufälligerweise Zeit. Wenn ich keine Zeit gehabt hätte, dann wäre etwas falsches im Thread stehen geblieben.

                        Viele Grüße,
                        Christian

                        --
                        Mein "Weblog" [RSS]
                        Using XSLT to create JSON output (Saxon-B 9.0 for Java)
                        »I don't believe you can call yourself a web developer until you've built an app that uses hyperlinks for deletion and have all your data deleted by a search bot.«
                                    -- Kommentar bei TDWTF
                    2. Hello,

                      Du hast nur einen Teil des gesamten Abschnitts zitiert und damit meine Aussage komplett verfälscht. Mir geht es wirklich nicht darum, im Recht zu sein und mich mit anderen Leuten zu "messen".

                      Jede Messung ist nur so gut, wie ihre Bewertbarkeit.
                      Ich bin auch noch nicht ganz fertig mit dem Nachvollziehen.

                      Da gibt es eine Stelle, an der ich noch stutze. Vielleicht ist es die Macke, vielleicht habe ich es auch nur noch nicht vollständig durchschaut. Aber das sollte bei Open Source Software doch auch einer der Sinne sein, alles nachvollziehen zu können und _nicht_ vertrauen zu _müssen_.

                      Kontrolle ist gut und dümmer wird man davon auch nicht.

                      Deine Leistung, lieber Christian, sollte hier überhaupt nicht in Frage gestellt werden. Ganz im gegenteil. Ich bin froh, dass Du ab und zu mal ein paar Insiderdinge genauer öffentlich unter die Lupe nimmst. Danke dafür!

                      Liebe Grüße aus dem schönen Oberharz

                      Tom vom Berg

                      --
                      Nur selber lernen macht schlau
                      http://bergpost.annerschbarrich.de
                4. Hi Christian,

                  (Disclaimer 2: Ein besserer Titel für dieses Posting wäre wohl gewesen: Mehr über die Interna von PHP, als das gesammelte SELFHTML-Forum je wissen wollte.)

                  ich faende besser: "Ein Einblick in PHP, der viel zu schade ist, um als Post in den unendlichen Weiten des Archives zu enden"

                  Toller Beitrag! Hast Du mal erwogen, daraus einen Fachartikel zu machen?

                  Viele Gruesse,
                  der Bademeister

                  1. Hallo,

                    Toller Beitrag! Hast Du mal erwogen, daraus einen Fachartikel zu machen?

                    Gute Idee, könnte man hübsch mit Bildchen und Diagrammen vervollständigen. Ich setze es mal auf meine (sehr, sehr, sehr, sehr, sehr lange) TODO-Liste. ;-)

                    Viele Grüße,
                    Christian

                    --
                    Mein "Weblog" [RSS]
                    Using XSLT to create JSON output (Saxon-B 9.0 for Java)
                    »I don't believe you can call yourself a web developer until you've built an app that uses hyperlinks for deletion and have all your data deleted by a search bot.«
                                -- Kommentar bei TDWTF
                    1. Ich setze es mal auf meine (sehr, sehr, sehr, sehr, sehr lange) TODO-Liste.

                      Ich machs mir hier natuerlich auch leicht, wenn ich anrege, dass andere Leute Fachartikel schreiben moegen. Nur in diesem Falle koenntest Du es ja fast schon auf die DONE-Liste setzen :-)

                      Viele Gruesse,
                      der Bademeister

                      1. Hallo,

                        Ich machs mir hier natuerlich auch leicht, wenn ich anrege, dass andere Leute Fachartikel schreiben moegen. Nur in diesem Falle koenntest Du es ja fast schon auf die DONE-Liste setzen :-)

                        Naja, nicht ganz. Wenn ich das als Fachartikel schreibe, dann packt mich der Ergeiz, das noch besser zu schreiben -> das wird mindestens nochmal so viel Arbeit wie das ursprünliche Posting.

                        Viele Grüße,
                        Christian

                        --
                        Mein "Weblog" [RSS]
                        Using XSLT to create JSON output (Saxon-B 9.0 for Java)
                        »I don't believe you can call yourself a web developer until you've built an app that uses hyperlinks for deletion and have all your data deleted by a search bot.«
                                    -- Kommentar bei TDWTF
                    2. [latex]Mae  govannen![/latex]

                      Gute Idee, könnte man hübsch mit Bildchen und Diagrammen vervollständigen. Ich setze es mal auf meine (sehr, sehr, sehr, sehr, sehr lange) TODO-Liste. ;-)

                      <?PHP  
                      echo('<pre>');  
                      print_r(array_reverse($users['seiler']['christian']['lists']['todo']));  
                      exit('</pre>');  
                      ?>
                      

                      Cü,

                      Kai

                      --
                      „It's 106 miles to Chicago, we got a full tank of gas, half a pack of cigarettes, it's dark, and we're wearing sunglasses“.
                      „Hit it!“
                      Selfzeugs
                      SelfCode: sh:( fo:| ch:? rl:( br:< n4:( ie:{ mo:| va:) js:| de:> zu:) fl:( ss:| ls:?
  2. Hallo Simone,

    $date_timestamp=forme_timestamp();  
    if([link:http://de2.php.net/manual/de/function.time.php@title=time]()-(30*24*3600)>= $date_timestamp) {/* mach was */}
    

    und den Rest? - den kannst Du sicher selber in Deiner Code einbauen

    Gruß aus Berlin!
    eddi

    --
    (v0.0.3 - also ganz der alte ;)