php-resource



Zurück   PHP-Scripte PHP-Tutorials PHP-Jobs und vieles mehr > Entwicklung > PHP Developer Forum
 

Login

 
eingeloggt bleiben
star Jetzt registrieren   star Passwort vergessen
 

 

 


PHP Developer Forum Hier habt ihr die Möglichkeit, eure Skriptprobleme mit anderen Anwendern zu diskutieren. Seid so fair und beantwortet auch Fragen von anderen Anwendern. Dieses Forum ist sowohl für ANFÄNGER als auch für PHP-Profis! Fragen zu Laravel, YII oder anderen PHP-Frameworks.

Antwort
 
LinkBack Themen-Optionen Thema bewerten
  #1 (permalink)  
Alt 23-06-2009, 22:26
phpMorpheus2
 Registrierter Benutzer
Links : Onlinestatus : phpMorpheus2 ist offline
Registriert seit: Apr 2007
Beiträge: 646
Blog-Einträge: 2
phpMorpheus2 ist zur Zeit noch ein unbeschriebenes Blatt
Standard Ausweg aus dem Referenzdilemma

Hallo.
Nocheinmal wende ich man an Euch

Ich verstehe folgende Aussage nicht:
Zitat:
Ausweg aus dem Referenzdilemma
Wie also kann man sicherstellen, daß eine Referenz auch als solche behandelt wird? In PHP gibt es dafür spezielle Syntax, bei der das Kaufmanns-Und den Referenz-Charakter einer Zuweisung oder einer Variablen-Betrachtung anzeigt:
PHP-Code:
$a = &$b;
$c =& $a;
$c 42
Die beiden obigen Zuweisung bewirken gleichermaßen, daß jeweils beide Variablen nicht nur denselben Wert haben, sondern auch eine Wertänderung einer der Variablen automatisch die exakt selbe Wertänderung der anderen Variablen bewirkt. Die letzte Anweisung bewirkt folglich, daß alle drei Variablen den Wert 42 annehmen.

Auch bei Funktions- und Methodenaufrufen wird normalerweise Kopiersemantik angewandt. Um explizit Referenzsemantik zu fordern, stellt man hierbei bei einer Funktions-/Methodendefinition einer zu referenzierenden Parameter-Variablen ein Kaufmanns-Und voran:
PHP-Code:
function Plus($var) { $var++; }
function 
Minus(&$var) { $var--; }
$var 42;
Plus($var);
Minus($var);
echo 
$var
Die Ausgabe obigen Codes ist natürlich 41, da nur die Funktion Minus den Wert der Variablen $var ändert. In Java wäre das nicht so offensichtlich, da hier u.U. eine Klassenvariable namens var existieren könnte, die implizit gemeint sein könnte. In PHP müßte man dann aber $this->var schreiben.

Unter 20.7.2 findet sich noch eine Übung zu komplexeren Anwendungen der Referenzsemantik.
Wovon ist gerade die Rede?
Obiger Code:
PHP-Code:
$a = &$b;
$c =& $a;
$c 42
bezieht sich auf eine Klasse, richtig?
Wenn ja, warum sollte $a = 42 sein?
Sie wird später definiert.
Also müssen die Variablen ja Objekte sein die angelegt wurden.
Folglich nehmen Objekte, auch wenn sie vorher definiert werden,
die Werte an, welche durch andere Objekte springen können (wenn definiert)
und so einen Wert ändern, trotz das diese vorher definiert wurden ?!?

Oder wie jetzt?
Das bringt mich zum Grübeln...
Mit Zitat antworten
  #2 (permalink)  
Alt 23-06-2009, 22:31
wahsaga
  Moderator
Links : Onlinestatus : wahsaga ist offline
Registriert seit: Sep 2001
Beiträge: 25.236
wahsaga befindet sich auf einem aufstrebenden Ast
Standard

Zitat:
Zitat von phpMorpheus2 Beitrag anzeigen
Obiger Code:
PHP-Code:
$a = &$b;
$c =& $a;
$c 42
bezieht sich auf eine Klasse, richtig?
Nein.

Zitat:
Wenn ja, warum sollte $a = 42 sein?
Sie wird später definiert.
Gerade deshalb, weil $c eine Referenz auf $a darstellt.

Zum Lesen: http://www.php.net/manual/de/language.references.php
__________________
I don't believe in rebirth. Actually, I never did in my whole lives.
Mit Zitat antworten
  #3 (permalink)  
Alt 23-06-2009, 23:27
combie
 PHP Expert
Links : Onlinestatus : combie ist offline
Registriert seit: May 2006
Beiträge: 3.296
combie wird schon bald berühmt werden
Standard

Zitat:
Das bringt mich zum Grübeln...
Das hat nix mit "Objecte" zu tun. Objecte werden seit PHP5 immer per Referenz übergeben. Es sei denn du Clonst sie.
__________________
Wir werden alle sterben
Mit Zitat antworten
  #4 (permalink)  
Alt 24-06-2009, 00:20
phpMorpheus2
 Registrierter Benutzer
Links : Onlinestatus : phpMorpheus2 ist offline
Registriert seit: Apr 2007
Beiträge: 646
Blog-Einträge: 2
phpMorpheus2 ist zur Zeit noch ein unbeschriebenes Blatt
Standard

Danke. Jetzt habe ich es verstanden.
Jede Referenz verändert also die ursprüngliche Variable.
Mit Zitat antworten
  #5 (permalink)  
Alt 24-06-2009, 00:47
phpMorpheus2
 Registrierter Benutzer
Links : Onlinestatus : phpMorpheus2 ist offline
Registriert seit: Apr 2007
Beiträge: 646
Blog-Einträge: 2
phpMorpheus2 ist zur Zeit noch ein unbeschriebenes Blatt
Standard

Ich hatte nicht gewusst,
das PHP4 den Zuweisungsoperator =& verwendet,
PHP5 jedoch nur = zum referenzieren benötigt.
Daher hat mich =& und = verwirrt.
Jetzt weiß ich, dass es die selben Zuweisungsoperatoren sind, = jedoch neuer ist.
Mit Zitat antworten
  #6 (permalink)  
Alt 24-06-2009, 00:51
wahsaga
  Moderator
Links : Onlinestatus : wahsaga ist offline
Registriert seit: Sep 2001
Beiträge: 25.236
wahsaga befindet sich auf einem aufstrebenden Ast
Standard

Zitat:
Zitat von phpMorpheus2 Beitrag anzeigen
Ich hatte nicht gewusst,
das PHP4 den Zuweisungsoperator =& verwendet,
PHP5 jedoch nur = zum referenzieren benötigt.
Daher hat mich =& und = verwirrt.
Jetzt weiß ich, dass es die selben Zuweisungsoperatoren sind, = jedoch neuer ist.
Das ist so allgemeingültig falsch.

Objekte werden unter PHP 5 immer per Referenz übergeben.
Für Skalare gilt das natürlich so nicht. Da braucht es immer noch das &, wenn mit Referenzen gearbeitet werden soll.
__________________
I don't believe in rebirth. Actually, I never did in my whole lives.
Mit Zitat antworten
  #7 (permalink)  
Alt 24-06-2009, 09:48
Benutzerbild von mermshaus mermshaus
 Registrierter Benutzer
Links : Onlinestatus : mermshaus ist offline
Registriert seit: Jun 2009
Beiträge: 451
mermshaus wird schon bald berühmt werden
Standard

Semi-Offtopic, weil es hier irgendwie passt:

Ein Array wird ebenfalls standardmäßig per Referenz übergeben, wenn sein Inhalt im Funktionskörper nicht verändert wird. Es scheint sich sogar negativ auf die Geschwindigkeit auszuwirken, dem Array (das nicht verändert wird) in der Funktionssignatur ein & voranzustellen.

Das ist natürlich eine nachvollziehbare Optimierung, aber weiß jemand, wo man das nachlesen kann?

Gruß Marc
Mit Zitat antworten
  #8 (permalink)  
Alt 24-06-2009, 09:59
unset
  Moderator
Links : Onlinestatus : unset ist offline
Registriert seit: Jan 2007
Ort: Düsseldorf
Beiträge: 3.782
unset befindet sich auf einem aufstrebenden Ast
Standard

Zitat:
Zitat von mermshaus Beitrag anzeigen
Ein Array wird ebenfalls standardmäßig per Referenz übergeben, wenn sein Inhalt im Funktionskörper nicht verändert wird.
Wie willst du das feststellen, wenn diese Referenz verfällt, sobald sich etwas ändert?
Mit Zitat antworten
  #9 (permalink)  
Alt 24-06-2009, 10:03
combie
 PHP Expert
Links : Onlinestatus : combie ist offline
Registriert seit: May 2006
Beiträge: 3.296
combie wird schon bald berühmt werden
Standard

Zitat:
Es scheint sich sogar negativ auf die Geschwindigkeit auszuwirken, dem Array (das nicht verändert wird) in der Funktionssignatur ein & voranzustellen.
Unglaublich, aber wahr!

Testcode:

PHP-Code:
function test1(Array $array)
{
    return 
count($array);
}

function 
test2(Array &$array)
{
    return 
count($array);

}


$array range(1,300000);





$start microtime(true);
for (
$i=0;$i<20;$i++)
{
  
test1($array);
}
$used microtime(true)-$start;
echo 
sprintf('%01.5f <hr>',$used);


$start microtime(true);
for (
$i=0;$i<20;$i++)
{
  
test2($array);
}
$used microtime(true)-$start;
echo 
sprintf('%01.5f <hr>',$used); 
__________________
Wir werden alle sterben
Mit Zitat antworten
  #10 (permalink)  
Alt 24-06-2009, 10:32
Benutzerbild von mermshaus mermshaus
 Registrierter Benutzer
Links : Onlinestatus : mermshaus ist offline
Registriert seit: Jun 2009
Beiträge: 451
mermshaus wird schon bald berühmt werden
Standard

Zitat:
Zitat von unset Beitrag anzeigen
Wie willst du das feststellen, wenn diese Referenz verfällt, sobald sich etwas ändert?
Ja, das hätte ich nicht so absolut ausdrücken sollen. Das ist die Vermutung aus den Benchmark-Zeiten.

Bei Strings ist es auch so:

Edit: Okay, vielleicht jetzt nicht gerade *die* Entdeckung.

PHP-Code:
ini_set('memory_limit''64M');

function 
test1($s)
{
    return 
strlen($s);
}

function 
test2(&$s)
{
    return 
strlen($s);
}


$s str_repeat(' '300000);





$start microtime(true);
for (
$i=0;$i<20;$i++)
{
  
test1($s);
}
$used microtime(true)-$start;
echo 
sprintf('%01.5f <hr>',$used);


$start microtime(true);
for (
$i=0;$i<20;$i++)
{
  
test2($s);
}
$used microtime(true)-$start;
echo 
sprintf('%01.5f <hr>',$used); 
Mit Zitat antworten
  #11 (permalink)  
Alt 24-06-2009, 10:59
unset
  Moderator
Links : Onlinestatus : unset ist offline
Registriert seit: Jan 2007
Ort: Düsseldorf
Beiträge: 3.782
unset befindet sich auf einem aufstrebenden Ast
Standard

Zitat:
Zitat von mermshaus Beitrag anzeigen
Ja, das hätte ich nicht so absolut ausdrücken sollen. Das ist die Vermutung aus den Benchmark-Zeiten.
Mir ging es eher um die Aussage, dass Arrays als Referenz übergeben werden, solange sich nichts an ihnen ändert. Wie hast du das herausgefunden?
Mit Zitat antworten
  #12 (permalink)  
Alt 24-06-2009, 11:09
Benutzerbild von onemorenerd onemorenerd
  Moderator
Links : Onlinestatus : onemorenerd ist offline
Registriert seit: Mar 2005
Ort: Berlin
Beiträge: 9.471
onemorenerd wird schon bald berühmt werdenonemorenerd wird schon bald berühmt werden
Standard

Das nennt sich Copy-On-Write und ist eine gängige Technik. Das Anlegen einer Kopie kostet Zeit und Speicher. Deshalb wird darauf verzichtet bis zum ersten Schreibzugriff.
Mit Zitat antworten
  #13 (permalink)  
Alt 24-06-2009, 11:39
Benutzerbild von mermshaus mermshaus
 Registrierter Benutzer
Links : Onlinestatus : mermshaus ist offline
Registriert seit: Jun 2009
Beiträge: 451
mermshaus wird schon bald berühmt werden
Standard

@unset:

Um die Aussage ging es mir auch, denn genau weiß (wusste ) ich nicht, ob das so ist, weil ich noch keine Dokumentation gefunden habe, die das bestätigt. Es ist nur der sinnvolle Schluss aus den Benchmarkergebnissen.

Bemerkt habe ich das, als ich einen Absatz zum Thema Codeoptimierung durch Übergabe von primitiven Datentypen (dazu habe ich das Array gezählt) als Referenz schreiben wollte und quasi den Benchmark von combie gebaut habe, um zu gucken, wie unglaublich viel Zeit man spart.

@onemorenerd:

Hast du auch eine Erklärung, wieso die Funktion test2() in combies Benchmark so lange braucht?

Kann man Primitive etwa gar nicht als "echte" Referenzen übergeben? Kopiert PHP die entsprechenden Daten intern trotzdem beim Aufruf hin und bei Funktionsende wieder zurück und gaukelt die entsprechende Funktionalität bloß vor? PHP: Passing by Reference - Manual

Das wäre eine krasse Bildungslücke.

Edit: Heißen die deshalb Primitive?
Edit2: Habe mir nie viel hierbei gedacht: "References in PHP are a means to access the same variable content by different names. They are not like C pointers; instead, they are symbol table aliases."

Geändert von mermshaus (24-06-2009 um 11:51 Uhr) Grund: Au wei au wei
Mit Zitat antworten
  #14 (permalink)  
Alt 24-06-2009, 13:53
Benutzerbild von onemorenerd onemorenerd
  Moderator
Links : Onlinestatus : onemorenerd ist offline
Registriert seit: Mar 2005
Ort: Berlin
Beiträge: 9.471
onemorenerd wird schon bald berühmt werdenonemorenerd wird schon bald berühmt werden
Standard

Diesen extremen Unterschied in combies Benchmark zweifle ich an. Hier mal ein anderer, bei dem die Tests nicht sequentiell sondern durch einzelne Requests und dadurch unter identischen Bedingungen ausgeführt werden. usleep() verwende ich als noop um zu verhindern, dass der Parser die Funktion oder den If-Block wegoptimiert.
PHP-Code:
<?php

function t_ ($a)                           { usleep(0); }
function 
t_ref (&$a)                       { usleep(0); }
function 
t_hint (array $a)                 { usleep(0); }
function 
t_hint_ref (array &$a)            { usleep(0); }
function 
t_read ($a)                       { if ($ausleep(0); }
function 
t_ref_read ($a)                   { if ($ausleep(0); }
function 
t_hint_read (array $a)            { if ($ausleep(0); }
function 
t_hint_ref_read (array &$a)       { if ($ausleep(0); }
function 
t_write ($a)                      { usleep(0); $a 0; }
function 
t_ref_write ($a)                  { usleep(0); $a 0; }
function 
t_hint_write (array $a)           { usleep(0); $a 0; }
function 
t_hint_ref_write (array &$a)      { usleep(0); $a 0; }
function 
t_read_write ($a)                 { if ($ausleep(0); $a 0; }
function 
t_ref_read_write ($a)             { if ($ausleep(0); $a 0; }
function 
t_hint_read_write (array $a)      { if ($ausleep(0); $a 0; }
function 
t_hint_ref_read_write (array &$a) { if ($ausleep(0); $a 0; }

header('Content-Type: text/plain');
if (isset(
$_GET['func']) && substr($_GET['func'], 02) == 't_' && isset($_GET['size']) && isset($_GET['runs'])) {
    
$orig range(1, (int)$_GET['size']);
    
$start microtime(true);
    for (
$i 0$i < (int)$_GET['runs']; $i++) {
        
$copy $orig;
        
$_GET['func']($copy);
    }
    echo 
sprintf("%01.5f µs - %d Bytes",
        
microtime(true) - $start,
        
memory_get_peak_usage(true));
}
else {
    
$url   'http://'.$_SERVER['HTTP_HOST'].$_SERVER['PHP_SELF'];
    
$runs  = isset($_GET['runs']) ? (int)$_GET['runs'] : 1000;
    
$size  = isset($_GET['size']) ? (int)$_GET['size'] : 1000;
    
$funcs get_defined_functions();

    echo 
"runs: $runs\nsize: $size\n";

    foreach (
$funcs['user'] as $func) {
        echo 
file_get_contents($url.'?func='.$func.'&size='.$size.'&runs='.$runs)." - $func\n";
    }
}
Code:
runs: 10000
size: 1000
0.09862 µs - 262144 Bytes - t_
0.75749 µs - 262144 Bytes - t_ref
0.09803 µs - 262144 Bytes - t_hint
0.75746 µs - 262144 Bytes - t_hint_ref
0.09851 µs - 262144 Bytes - t_read
0.09817 µs - 262144 Bytes - t_ref_read
0.09805 µs - 262144 Bytes - t_hint_read
0.75787 µs - 262144 Bytes - t_hint_ref_read
0.09879 µs - 262144 Bytes - t_write
0.09921 µs - 262144 Bytes - t_ref_write
0.09975 µs - 262144 Bytes - t_hint_write
0.76339 µs - 262144 Bytes - t_hint_ref_write
0.09973 µs - 262144 Bytes - t_read_write
0.10127 µs - 262144 Bytes - t_ref_read_write
0.10139 µs - 262144 Bytes - t_hint_read_write
0.76083 µs - 262144 Bytes - t_hint_ref_read_write
Mein Fazit:
Type Hints allein kosten fast nichts.
Referenzen allein kosten fast nichts.
Type Hints auf Referenzen sind teuer.

Warum das so ist kann ich aus dem Stand nicht sagen. Wenn du es unbedingt wissen willst, schau in den Source Code des Interpreters. Mir ist der Unterschied zu gering, ich mach mir da keinen Kopf.

Übrigens kannst du bei diesem Benchmark mal langsam Size hoch schrauben und wirst sehen, dass Type Hints auf Referenzen auch mehr Speicher brauchen.

http://derickrethans.nl/files/phparc...es-article.pdf Unbedingt lesen!
Mit Zitat antworten
  #15 (permalink)  
Alt 24-06-2009, 15:33
Benutzerbild von mermshaus mermshaus
 Registrierter Benutzer
Links : Onlinestatus : mermshaus ist offline
Registriert seit: Jun 2009
Beiträge: 451
mermshaus wird schon bald berühmt werden
Standard

Edit: Kommando zurück. Im Benchmark-Code war noch eine Zeile $copy = $orig, die ich übersehen hatte. Das heißt, es existieren bereits zwei Bezeichner, die auf denselben Inhalt zeigen. Wenn dann auf einen der beiden noch eine Referenz gesetzt wird, dann wird wohl kopiert, iirc (siehe Artikel). Jedenfalls sind dann die Benchmark-Zeiten gleich ganz anders, wenn die entsprechende Zeile auskommentiert und $orig übergeben wird.


Den Artikel hatte ich auch gefunden und ich denke mal, Figure 7 sollte unserem Problem hier entsprechen. Allerdings sehe ich da nicht, wo bei Aufruf der Inhalt der per Referenz an die Funktion übergebenen Variable kopiert wird (oder ähnliches). Das sieht für mich so aus, als würde da nur ein zweiter "Zeiger" auf denselben Speicherinhalt gesetzt. Wo geht da die Zeit verloren (siehe unten)?

Vielen Dank für den Benchmark! Der sieht von Aufbau sehr gelungen aus. Allerdings hast du in den Funktionsdeklarationen ein paar Referenzen vergessen und ich glaube außerdem, dass das Schreiben eher mit $a[0] = 0; geprüft werden sollte, da er sonst nicht zu "copy on write" gezwungen ist. (Könnte zudem sprintf die memory_get_peak_usage bei kleiner $size beeinflussen? Das habe ich jetzt nicht getestet.)

Mit den beschriebenen Änderungen ergibt sich:

Code:
runs: 10000
size: 1000

0.70719 µs - 262144 Bytes - t_
2.92888 µs - 262144 Bytes - t_ref
0.62768 µs - 262144 Bytes - t_hint
2.35741 µs - 262144 Bytes - t_hint_ref

0.64666 µs - 262144 Bytes - t_read
2.45519 µs - 262144 Bytes - t_ref_read
0.64916 µs - 262144 Bytes - t_hint_read
2.31166 µs - 262144 Bytes - t_hint_ref_read

2.33536 µs - 262144 Bytes - t_write
2.43142 µs - 262144 Bytes - t_ref_write
2.43154 µs - 262144 Bytes - t_hint_write
2.25035 µs - 262144 Bytes - t_hint_ref_write

2.05961 µs - 262144 Bytes - t_read_write
2.41068 µs - 262144 Bytes - t_ref_read_write
2.45428 µs - 262144 Bytes - t_hint_read_write
2.45996 µs - 262144 Bytes - t_hint_ref_read_write
Wenn ich keinen Unsinn gemacht habe, sind die Referenzen also immer langsam.

Habe mir ein wenig was abgeguckt und noch mal ein anderes Beispiel versucht:

PHP-Code:
header('content-type: text/plain');

$array range(130000);            echo memory_get_peak_usage(), " - start\n";

if (
is_array($array)) { usleep(0); } echo memory_get_peak_usage(), " - is_array(original)\n";

$a = &$array;                        echo memory_get_peak_usage(), " - copy to ref\n";

$a[0] = 0;                           echo memory_get_peak_usage(), " - write ref\n";

if (
$a[0]) { usleep(0); }            echo memory_get_peak_usage(), " - read ref\n";

if (
is_array($a)) { usleep(0); }     echo memory_get_peak_usage(), " - is_array(ref)\n"
Ausgabe:

Code:
3187556 - start
3187660 - is_array(original)
3187724 - copy to ref
3187724 - write ref
3187724 - read ref
5118904 - is_array(ref)
Ich kann mir noch keinen Reim drauf machen, weiß aber aktuell auch nicht mehr, was sich eigentlich zu messen lohnt.

Edit: http://bugs.php.net/bug.php?id=34540 *schulterzuck*

Vorläufiges Fazit: Es ist vermutlich immer eine sehr ineffiziente Idee ist, Arrays als Referenz zu übergeben.

Geändert von mermshaus (24-06-2009 um 15:52 Uhr) Grund: Sorry für das Chaos
Mit Zitat antworten
Antwort

Lesezeichen


Aktive Benutzer in diesem Thema: 1 (Registrierte Benutzer: 0, Gäste: 1)
 

Themen-Optionen
Thema bewerten
Thema bewerten:

Forumregeln
Es ist Ihnen nicht erlaubt, neue Themen zu verfassen.
Es ist Ihnen nicht erlaubt, auf Beiträge zu antworten.
Es ist Ihnen nicht erlaubt, Anhänge hochzuladen.
Es ist Ihnen nicht erlaubt, Ihre Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are an


PHP News

ebiz-trader 7.5.0 mit PHP7 Unterstützung veröffentlicht
ebiz-trader 7.5.0 mit PHP7 Unterstützung veröffentlichtDie bekannte Marktplatzsoftware ebiz-trader ist in der Version 7.5.0 veröffentlicht worden.

28.05.2018 | Berni

Wissensbestand in Unternehmen
Wissensbestand in UnternehmenLebenslanges Lernen und Weiterbilden sichert Wissensbestand in Unternehmen

25.05.2018 | Berni


 

Aktuelle PHP Scripte

PHP Server Monitor

PHP Server Monitor ist ein Skript, das prüft, ob Ihre Websites und Server betriebsbereit sind.

11.09.2018 Berni | Kategorie: PHP/ Security
PHP WEB STATISTIK ansehen PHP WEB STATISTIK

Die PHP Web Statistik bietet Ihnen ein einfach zu konfigurierendes Script zur Aufzeichnung und grafischen und textuellen Auswertung der Besuchern Ihrer Webseite. Folgende zeitlichen Module sind verfügbar: Jahr, Monat, Tag, Wochentag, Stunde Folgende son

28.08.2018 phpwebstat | Kategorie: PHP/ Counter
Affilinator - Affilinet XML Produktlisten Skript

Die Affilinator Affilinet XML Edition ist ein vollautomatisches Skript zum einlesen und darstellen der Affili.net (Partnerprogramm Netzwerk) Produktlisten und Produktdaten. Im Grunde gibt der Webmaster seine Affilinet PartnerID ein und hat dann unmittelb

27.08.2018 freefrank@ | Kategorie: PHP/ Partnerprogramme
 Alle PHP Scripte anzeigen

Alle Zeitangaben in WEZ +2. Es ist jetzt 01:14 Uhr.