WN

WN (https://www.wn.se/forum/index.php)
-   Serversidans teknologier (https://www.wn.se/forum/forumdisplay.php?f=4)
-   -   PHP 4 + PHP 5 construkt : kalla på PHP 4 c eller g (https://www.wn.se/forum/showthread.php?t=8582)

lord mazdak 2005-06-21 17:24

Vi säger att vi har denna classen :

Kod:

class DB
{
        var $host; // The hostname
        var $user; // The username
        var $password; // The password
        var $database; // The database

        function DB($host,$user,$password,$database) // PHP4 class constructor
        {
 // populate the properties thats needed for connection
 $this->host = $host;
 $this->user = $user;
 $this->password = $password;
 $this->database = $database;
        }
// lite andra metoder
}

nu vill man göra så att PHP 5 kan få använda sin egen construktor syntax och inte använda PHP 5s "backward compability"

då kan man ju göra såhär
Kod:

class DB
{
        var $host; // The hostname
        var $user; // The username
        var $password; // The password
        var $database; // The database

        function DB($host,$user,$password,$database) // PHP4 class constructor
        {
 // populate the properties thats needed for connection
 $this->host = $host;
 $this->user = $user;
 $this->password = $password;
 $this->database = $database;
        }

        function __construct($host,$user,$password,$database) // PHP5 class constructor
        {
        {
 $this->DB($host,$user,$password,$database);
        }
// lite andra metoder
}

eller såhär

Kod:

class DB
{
        var $host; // The hostname
        var $user; // The username
        var $password; // The password
        var $database; // The database

        function DB($host,$user,$password,$database) // PHP4 class constructor
        {
 // populate the properties thats needed for connection
 $this->host = $host;
 $this->user = $user;
 $this->password = $password;
 $this->database = $database;
        }

        function __construct($host,$user,$password,$database) // PHP5 class constructor
        {
 // populate the properties thats needed for connection
 $this->host = $host;
 $this->user = $user;
 $this->password = $password;
 $this->database = $database;
        }
// lite andra metoder
}

Vilket går snabbast av de 2 senare kodstyckerna ?
Och ska man ta med PHP 5s construct och göra så att prestandan sjunker för PHP 4 användarna eller ska PHP 5 användarna få sämre prestanda ( då kör man utan PHP 5s construct

eg0master 2005-06-21 18:20

Självklart medför ett extra funktionsanrop att (när php5 konstruktorn anropar php4 konstruktorn) att det tar längre tid, men i praktiken så är nog deta en fis i havet jämfört med vad resten av sidan tar att parsa.

Skriv ett testscript som instansierar klassen flera tusen gånger och mät tiden så har du svaret.

lord mazdak 2005-06-21 19:41

hur var det nu man fick reda på execution time?

kullervo 2005-06-22 00:14

Citat:

Originally posted by lord mazdak@Jun 21 2005, 18:41
hur var det nu man fick reda på execution time?
time() och utime() finns ju alltid.

eg0master 2005-06-22 07:48

eller varför inte microtime...
microtime hjälpen på php.net har ett bra exempel.

kullervo 2005-06-22 10:21

Citat:

Originally posted by eg0master@Jun 22 2005, 06:48
eller varför inte microtime...
microtime hjälpen på php.net har ett bra exempel.

Hoppsan. Trodde den hette utime().

lord mazdak 2005-06-22 14:55

Gjorde lite benchmarks med dessa script

1.
Kod:

<?php
$mtime = microtime();
$mtime = explode(" ",$mtime);
$mtime = $mtime[1] + $mtime[0];
$starttime = $mtime;

class DB
{
        var $host;
        var $user;
        var $password;
        var $database;

        function DB($host,$user,$password,$database) // PHP4 class constructor
        {
 $this->host = $host;
 $this->user = $user;
 $this->password = $password;
 $this->database = $database;
        }

        function __construct($host,$user,$password,$database) // PHP5 class constructor
        {
 $this->host = $host;
 $this->user = $user;
 $this->password = $password;
 $this->database = $database;
        }
}

for($i = 0; $i < 100000; $i++)
{
        $instance = new DB('host','user','password','database');
}

$mtime = microtime();
$mtime = explode(" ",$mtime);
$mtime = $mtime[1] + $mtime[0];
$endtime = $mtime;
$totaltime = ($endtime - $starttime);
echo "execution time = $totaltime seconds<br/>instances maid = $i<br/>average execution time/instance = ".$totaltime / $i;
?>

2.
Kod:

<?php
$mtime = microtime();
$mtime = explode(" ",$mtime);
$mtime = $mtime[1] + $mtime[0];
$starttime = $mtime;

class DB
{
        var $host;
        var $user;
        var $password;
        var $database;

        function DB($host,$user,$password,$database) // PHP4 class constructor
        {
 $this->host = $host;
 $this->user = $user;
 $this->password = $password;
 $this->database = $database;
        }

        function __construct($host,$user,$password,$database) // PHP5 class constructor
        {
 $this->DB($host,$user,$password,$database);
        }
}

for($i = 0; $i < 100000; $i++)
{
        $instance = new DB('host','user','password','database');
}

$mtime = microtime();
$mtime = explode(" ",$mtime);
$mtime = $mtime[1] + $mtime[0];
$endtime = $mtime;
$totaltime = ($endtime - $starttime);
echo "execution time = $totaltime seconds<br/>instances maid = $i<br/>average execution time/instance = ".$totaltime / $i;
?>

1:an gav dessa resultat ( det sista fixade jag )
Kod:

execution time = 2,03122901917 seconds
instances maid = 100000
average execution time/instance = 0,0000203122901917

execution time = 2,01193809509 seconds
instances maid = 100000
average execution time/instance = 0,0000201193809509

execution time = 1,98479390144 seconds
instances maid = 100000
average execution time/instance = 0,0000198479390144

execution time = 1,99218416214 seconds
instances maid = 100000
average execution time/instance = 0,0000199218416214

execution time = 2,01383900642 seconds
instances maid = 100000
average execution time/instance = 0,0000201383900642

execution time = 2,13474011421 seconds
instances maid = 100000
average execution time/instance = 0,0000213474011421

execution time = 1,98517394066 seconds
instances maid = 100000
average execution time/instance = 0,0000198517394066

execution time = 2,01875305176 seconds
instances maid = 100000
average execution time/instance = 0,0000201875305176

execution time = 2,08163309097 seconds
instances maid = 100000
average execution time/instance = 0,0000208163309097

execution time = 2,01121997833 seconds
instances maid = 100000
average execution time/instance = 0,0000201121997833

Total (10 executions):
execution time = 20,26550436019
instances maid = 1000000
average execution time/instance = 0,00002026550436019

och 2:an gav dessa resultat
Kod:

execution time = 2,88538885117 seconds
instances maid = 100000
average execution time/instance = 0,0000288538885117

execution time = 2,87395501137 seconds
instances maid = 100000
average execution time/instance = 0,0000287395501137

execution time = 3,01868104935 seconds
instances maid = 100000
average execution time/instance = 0,0000301868104935

execution time = 3,03595113754 seconds
instances maid = 100000
average execution time/instance = 0,0000303595113754

execution time = 3,09631586075 seconds
instances maid = 100000
average execution time/instance = 0,0000309631586075

execution time = 3,01692414284 seconds
instances maid = 100000
average execution time/instance = 0,0000301692414284

execution time = 2,92553091049 seconds
instances maid = 100000
average execution time/instance = 0,0000292553091049

execution time = 3,00412797928 seconds
instances maid = 100000
average execution time/instance = 0,0000300412797928

execution time = 3,09196591377 seconds
instances maid = 100000
average execution time/instance = 0,0000309196591377

execution time = 3,02725505829 seconds
instances maid = 100000
average execution time/instance = 0,0000302725505829

Total (10 executions):
execution time = 29,97609591485
instances maid = 1000000
average execution time/instance = 0,00002997609591485

Slutsats :
Det går snabbare att ge egenskaperna ett värde igen än att kalla på PHP 4 konstruktorn

eg0master 2005-06-22 17:01

Citat:

Originally posted by lord mazdak@Jun 22 2005, 14:55
[...]
1:an gav dessa resultat ( det sista fixade jag )
Kod:

[...]
execution time = 1,98517394066 seconds
instances maid = 100000
average execution time/instance = 0,0000198517394066
[...]

och 2:an gav dessa resultat
Kod:

[...]
execution time = 3,09631586075 seconds
instances maid = 100000
average execution time/instance = 0,0000309631586075
[...]

Slutsats :
Det går snabbare att ge egenskaperna ett värde igen än att kalla på PHP 4 konstruktorn

Ordpolisen: Jag tror du menar made och inte maid, fast egentligen menar du nog created... :P

Det du kallar slutsats är egentligen bara ett konstaterande/bevis för att något vi redan visste är sant.

Diskussion:
Jag valde snabbaste tiden för den snabba lösningen och den långsamaste för den långsamma. Detta ger en skillnad på 1,111 sekunder lite drygt. Detta då 100K instanser skapas. Detta ger en overhead på drygt 11 ms per instansiering.
Samtidigt är ju lösningen där php5 konstruktorn anropar php4 konstruktorn lättare att underhålla eftersom förändringar bara behöver göras på ett ställe istf två.

Slutsats:
Man måste titta på hur mycket man tjänar i exekveringstid kontra eventuella problem med att underhålla två identiska funktioner.

Personlig kommentar:
Jag tvivlar på att du skapar 100K instanser per sida... och även om du gjorde det så hur stor del av hela sidans exekveringstid är då 1s?
Du skall inte optimera saker som inte behöver optimeras. 11ms/anrop känns inte värt besväret med tanke på det du förlorar i underhållbarhet av koden. Möjligen är det värt det om du kansk spara flera sekunder per sida, men allvarligt talat - om du skapar ett par, tre hundra objekt per sida så känns det som något annat är fel i din design...

kullervo 2005-06-23 01:20

Citat:

Originally posted by eg0master@Jun 22 2005, 16:01
Diskussion:
Jag valde snabbaste tiden för den snabba lösningen och den långsamaste för den långsamma. Detta ger en skillnad på 1,111 sekunder lite drygt. Detta då 100K instanser skapas. Detta ger en overhead på drygt 11 ms per instansiering.
Samtidigt är ju lösningen där php5 konstruktorn anropar php4 konstruktorn lättare att underhålla eftersom förändringar bara behöver göras på ett ställe istf två.

Om det skulle ta 11ms längre tid så skulle åtminstonde jag köra den snabbare metoden. 11ms är mycket. Däremot har du räknat fel på två decimaler.

eg0master 2005-06-23 11:48

Citat:

Originally posted by kullervo@Jun 23 2005, 01:20
Om det skulle ta 11ms längre tid så skulle åtminstonde jag köra den snabbare metoden. 11ms är mycket. Däremot har du räknat fel på två decimaler.
Räknat fel på två decimaler? hur menar du? Snarare tre tiopotenser... Ser att jag söp och korrigerade för ms vid uträkningen. Rätt tid per anrop är ju 0.011 ms. Vilket ännu mer övertygande för att man inte skall använda sig av "fulvarianten" och ha redundant kod.

Och 11ms kan du inte säga är mycket utan att säga vad det jämförs med. 11ms av något som tar 3s är lite. 11ms av något som tar 12ms är mycket.

Tvartom 2005-06-27 20:57

Det bör väl även beaktas hur lång tid det tar att kompilera de olika scripten?

Det är lite beroende på servern konfiguration, men kompileras scriptet till
vart anrop kan det vara av större betydelse, lite beroende på hur classen
används i scripten.

lord mazdak 2005-06-28 14:19

Klassen instansieras 1 gång på varje sida :P
När jag väl vet vad som går snabbast så tar jag den snabbare varianten

eg0master 2005-06-28 16:35

Citat:

Originally posted by lord mazdak@Jun 28 2005, 14:19
Klassen instansieras 1 gång på varje sida :P
När jag väl vet vad som går snabbast så tar jag den snabbare varianten

Om du väljer det som är "snabbast" i exekveringstid så fattar du fel beslut. Att låta en konstruktor anropa en annan är betydligt bättre eftersom du då får all konstruktorkod på ett enda ställe. det tjänar du på i längden. att ha allt på två ställen kommer garanterat leda till att du (eller någon annan) i framtiden råkar ändra på bara det ena stället.
Speciellt om det handlar om en enda instans.

Som jag skrev tidigare - du skall inte optimera fel saker. lös rätt problem!

lord mazdak 2005-06-28 16:47

I det här fallet så behöver man knappast ändra på konstruktorn.
Det är bara att ge 4 engenskaper ett värde.
Resten av classen sköts av andra metoder.

eg0master 2005-06-28 21:37

Citat:

Originally posted by lord mazdak@Jun 28 2005, 16:47
I det här fallet så behöver man knappast ändra på konstruktorn.
Det är bara att ge 4 engenskaper ett värde.
Resten av classen sköts av andra metoder.

ja så är det kanske den här gången och alla säger nästa gång när jag har mer grejer så gör jag på ett annat sätt. Det du gör är ett typiskt nybörjarfel - men vill du göra det så visst. Jag ska inte tvinga dig. "Så som man tränar - spelar man" är ett talesätt som passar in här...

lord mazdak 2005-06-28 22:12

Varför skulle en DB abstraction layers konstruktor behöva ändring om classen är skriven som min
Ge mig 1 passande senario då jag skulle behöva ändra på den.
Hela Klassen :
Kod:

<?php
/*--------------------------------------------
|        file = db/mysql.php
|        description : A database class
|        --------------
|        copyright = (C) 2005 The Magicasoft Group
|        email = [email protected]
*-------------------------------------------*/

class DB
{
        var $host; // The hostname
        var $user; // The username
        var $password; // The password
        var $database; // The database
        var $conn = array('server' => 0, 'database' => 0); // Database and Server connection recource
        var $query = array(); // The exsisting querys
        var $currMethod; // The last result
        var $lang_struct = array('text' => 'TEXT',
        'primkey const' => 'NOT NULL auto_increment',
        'primkey' => 'PRIMARY KEY (#2)',
        'spec prim' => '',
        'primkey dt int' => 'INTEGER(#1)');

        function DB($host,$user,$password,$database) // PHP4 class constructor
        {
 // populate the properties thats needed for connection
 $this->host = $host;
 $this->user = $user;
 $this->password = $password;
 $this->database = $database;
        }

        function __construct($host,$user,$password,$database) // PHP5 class constructor
        {
 // populate the properties thats needed for connection
 $this->host = $host;
 $this->user = $user;
 $this->password = $password;
 $this->database = $database;
        }

        function connect($errormode = 'print') // connect to the database
        {
 if($errormode === 'return')
 {
        $ext_test = ( function_exists('mysql_connect') ? '' : -1);
        if($ext_test === -1) return -1;
        $this->conn['server'] = @mysql_connect($this->host,$this->user,$this->password);
        return (@mysql_select_db($this->database,$this->conn['server']) ? 1 : 0);
 }

 $this->conn['server'] = mysql_connect($this->host,$this->user,$this->password) or $this->error('Can\'t connect to the server');
 $this->conn['database'] = mysql_select_db($this->database,$this->conn['server']) or $this->error('Can\'t connect to the database');
        }

        function close() // close the database connection
        {
 $this->query = NULL;
 mysql_close($this->conn['server']);
        }

        function query($query,$queryname,$overwrite = 'no') // run a query
        {
 if(!isset($this->query[$queryname]) || $overwrite === 'yes') // make sure there is no chance of unwanted conlicts with queries
 {
        $this->query[$queryname] = $this->currMethod = mysql_query($query,$this->conn['server']) or $this->error($queryname.' invalid query');
        return $this->currMethod;
 }
 else $this->error('Can\t overwrite query : '.$queryname); // display error
        }

        function fetch_row($queryname) // fetch a row as an array
        {
 $this->currMethod = mysql_fetch_row($this->query[$queryname]);
 return $this->currMethod;
        }

        function fetch_assoc($queryname,$load = 'yes') // fetch a row as an hash
        {
 if($load === 'no') // check if query is outside $this->query
 {
        $this->currMethod = mysql_fetch_assoc($queryname);
        return $this->currMethod;
 }
 else
 {
        $this->currMethod = mysql_fetch_assoc($this->query[$queryname]);
        return $this->currMethod;
 }
        }

        function num_rows($queryname) // get the number of rows in a query
        {
 if(mysql_num_rows($this->query[$queryname]))
 {
        $this->currMethod = (string)mysql_num_rows($this->query[$queryname]) or $this->error('Can\'t get the number of rows from query : '.$queryname);
        return (int)$this->currMethod;
 }
        }

        function showcolumns($table,$keep = 'no') // show the columns of a table
        {
 $this->query("SHOW COLUMNS FROM $table",'showcolumns_'.$table);
 while($col = $this->fetch_assoc('showcolumns_'.$table))
 {
        extract($col);
        $columns[$Field]['name'] = $Field;
        $Type = explode('(',$Type);
        $columns[$Field]['type'] = $Type[0];
        $columns[$Field]['maxlength'] = str_replace(')','',$Type[1]);
 }
 $this->currMethod = $columns;
 
 if($keep === 'no') unset($this->query['showcolumns_'.$table]);
 
 return $this->currMethod;
        }

        function ALTER_TABLE($table,$action,$column,$type = '',$length = '',$newcolumn = '') // add,edit,delete columns from a table
        {
 if($action === 'add') // handle adding columns
 {
        $this->query("ALTER TABLE {$table} ADD COLUMN {$column} {$type}{$length} NOT NULL",'alter-table-add_sql');
 }
 elseif($action === 'edit') // handle editing columns
 {
        $this->query("ALTER TABLE {$table} RENAME {$column} TO {$newcolumn}",'alter-table-edit_sql');
        $this->query("ALTER TABLE {$table} MODIFY {$newcolumn} {$type}{$length} NOT NULL",'alter-table-edit_sql','yes');
 }
 elseif($action === 'delete') // handle deleting columns
 {
        $this->query("ALTER TABLE {$table} DROP COLUMN {$column}",'alter-table-delete_sql');
 }
        }

        function lang() // get a sql language structure
        {
 $num_args = func_num_args(); // number of arguments
 if($num_args === 0) trigger_error('Invalid argument count for function : lang, the function need atleast 1 argument',E_USER_ERROR); // function can't be void
 elseif($num_args === 1) return $this->lang_struct[func_get_arg(0)]; // if only 1 argument the return the language stucture
 else // handle language structures with arguments/variables
 {
        $code = $this->lang_struct[func_get_arg(0)];
       
        for($i = 1; $i < $num_args; $i++)
        {
  ${$i} = func_get_arg($i);
  $code = preg_replace('/#'.$i.'/',$$i,$code);
        }
        return $code;
 }
        }

        function error($msg) // display the last error and terminate
        {
 $error = mysql_error();
 $errorcode = mysql_errno();

 $message = 'Database error in Magicasoft BBman 2:'.$msg.'
 Database Error:'.error.'
 Error Code: '.$errorcode.'
 Date: '.date('F j, Y h:i A').'
 Script: '.$_SERVER['REQUEST_URI'];
 echo'
 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
 <html>
 <head>
 <title>Magicasoft BBman 2 Database Error</title>
 <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
 <style type="text/css">
 body, p
 {
        font-family: verdana,arial,helvetica,sans-serif;
        font-size: 11px;
 }
 </style>
 </head>
 <body>
 <blockquote><p><strong>Fatal error caused by fault in database.</strong><br/>
 You may try this action again by pressing <a href="javascript:window.location=window.location;">refresh</a>.</p>
 <p>We apologise for any inconvenience.</p>
 <form action="null"><textarea rows="10" cols="55">'.$message.'</textarea></form>
 </blockquote>
 </body>
 </html>';
 die;
        }
}
?>


eg0master 2005-06-28 23:57

Du förstår inte poängen. Genom att göra på ett visst sätt i detta fall är risken/chansen stor att du (eller någon annan som tittar på din kod och skall göra tillägg) gör på samma sätt i andra klasser och förr eller senare kommer det en klass som ändras, men bara på ett ställe. Om du vill gömma dig bakom argument som "bara jag ska hålla på med det här", "när det verkligen behövs kommer jag göra på ett annat sätt" eller "Jag kommer aldrig behöva ändra något i den här klassen" så kan vi sluta diskussionen nu. Jag kommer med tips för att generellt skapa en snyggare och mer lätthanterad kod eftersom prestandavinsten är försumbar i sammanhanget (optimera rätt sak som jag skrev tidigare).

men vill du ha förslag på ändringar? Några mer eller mindre rimliga förändringar:
- host skall i konstruktorn skrivas om till ett IP-nummer
- alla värden skall ha defaultvärden om de är tomma
- php kommer med ett nytt mysql interface som kräver nya parametrar som inte fanns tidigare
- Du vill använda en annan databas än mysql vars interface i php kräver fler parametrar

Trust me - du kommer inte ångra dig om du låter den ena konstruktorn anropa den andra. Det kan jag garantera. Om du däremot duplicerar kod kanske du inte kommer ångra dig - men det är inte säkert. Det här handlar inte längre om din lilla databasklass. Det handlar om generella principer där kodens läsbarhet och underhålls egenskaper är i ena vågskålen och prestanda i den andra. Det handlar om att välja att optimera sin kod för rätt saker. Något som kan ta ett tag att lära sig. Men du slipper. Kör du med cut-n-paste kod.

lord mazdak 2005-06-29 04:09

saxat från php.net :
"For backwards compatibility, if PHP 5 cannot find a __construct() function for a given class, it will search for the old-style constructor function, by the name of the class."

Vill The PHP Group vara snälla och berätta för mig varför classen DB ger följande fel ger:
Debug Strict (PHP 5): C:\wamp\www\projects\bbman\wd\db\mysql.php line 34 - Redefining already defined constructor for class DB

Detta betyder att PHP5 först hittar DB() som konstruktor och sedan hittar __construct()
Om det är något som ska redefinera det andra så är det DB()

ännu löng från The PHP Group

1. Förklara mer om "host skall i...", varför?, går det att ansluta till alla databaser (som går att ansluta till genom host) genom ip?
2. Tack för tipset fast det görs väl inte i konstruktorn.
3. MySQL Improved är redan känt för mig och det finns en klass för det, inga skillnader på konstruktorn fast på andra metoder.
4. Till projektet finns det 8 olika classer för 8 olika api:s som alla har en konstruktor som ser likadan ut. Be mig inte att posta dem det e mer än 1000 rader kod sammanlagt om ngn vill ha dem så finns alla i projektet BBman2 (magicasoft.net)

Tror att jag skippar PHP 5 construktorn tillsvidare

eg0master 2005-06-29 08:57

jag tror jag ger upp mitt korståg...

Men för att svara på dina frågor:
1a) Jag kanske vill bespara mig en DNS uppslagning i ett senare tillfälle?
1b) vet du inte att ett namn bara är ett alias för en IP adress?
2) Skulle kunna göras där.
3) Och vad vet du om "MySQL super improved++" som inte ens börjat skapas ännu?
4) Ja och dessa 8 klasser är ju självklart allt som någonsin behövs.
Bonus) Nej jag ber dig att inte posta mer kod för det mesta av koden (allt utom konstruktorerna) har ju varit irrelevant.

lord mazdak 2005-06-29 09:19

1a) lagt det till min todo till nästa version detta borde tillhöra "optimera rätt grej" delen
1b) Klantade mig oerhört. sorry :D sh*t happens
2) tar det när variablerna skapas.

Diskutionen stannar nog här.


Alla tider är GMT +2. Klockan är nu 23:24.

Programvara från: vBulletin® Version 3.8.2
Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
Svensk översättning av: Anders Pettersson