FAQ |
Kalender |
|
![]() |
#1 | ||
|
|||
Klarade millennium-buggen
|
Jag har testat lite OOP med PHP och autoloader som jag tänkte dela med mig av:
Först min testklass: Kod:
<?php // File: TestAutoloader.php // Author: Conny Westh 2012-09-13 require_once('/lib/autoloader.php'); try { print "Test av autoloader.php\n"; $c1 = new MyClass1(); $c2 = new MyClass2(); } catch (Exception $e) { print $e->getMessage(); } ?> Kod:
<?php class MyClass1 { public static function run() { print "MyClass1 Works just fine...\n"; } } $className = 'MyClass1'; $className::run(); ?> Kod:
<?php class MyClass2 { public static function run() { print "MyClass2 Works just fine...\n"; } } $className = 'MyClass2'; $className::run(); ?> Autoloader-klassen kan man lägga i en underkatalog som lämpligtvid heter LIB: Kod:
<?php // File: autoloader.php // Modified by Conny Westh 2012-09-13 class autoloader { public static $loader; public static function init() { if (self::$loader == NULL) self::$loader = new self(); return self::$loader; } public function __construct() { spl_autoload_register(array($this,'approot')); spl_autoload_register(array($this,'model')); spl_autoload_register(array($this,'helper')); spl_autoload_register(array($this,'controller')); spl_autoload_register(array($this,'library')); } public function approot($class) { set_include_path(get_include_path().PATH_SEPARATOR.'/'); spl_autoload_extensions('.php'); spl_autoload($class); } public function library($class) { set_include_path(get_include_path().PATH_SEPARATOR.'/lib/'); spl_autoload_extensions('.php'); spl_autoload($class); } public function controller($class) { $class = preg_replace('/_controller$/ui','',$class); set_include_path(get_include_path().PATH_SEPARATOR.'/controller/'); spl_autoload_extensions('.php'); spl_autoload($class); } public function model($class) { $class = preg_replace('/_model$/ui','',$class); set_include_path(get_include_path().PATH_SEPARATOR.'/model/'); spl_autoload_extensions('.php'); spl_autoload($class); } public function helper($class) { $class = preg_replace('/_helper$/ui','',$class); set_include_path(get_include_path().PATH_SEPARATOR.'/helper/'); spl_autoload_extensions('.php'); spl_autoload($class); } } //call autoloader::init(); ?> |
||
![]() |
![]() |
![]() |
#2 | ||
|
|||
Administratör
|
Citat:
PSR-0 har blivit en väl vedertagen standard för autoloading. Den ger dig interopabilitet mellan annan välskriven kod. https://github.com/php-fig/fig-stand...epted/PSR-0.md Vidare är en full include_path baserad autoloading långsam samt mer error-prone och svåröveriktlig då du faktiskt måste åt en server-variabel för att se hela dess innebörd. Projektet blir alltså beroende av någon utanför projektet i sig. De flesta välskrivna projekt som har använt detta tidigare har använt en classmap generator för att lättare kunna överblicka och få bättre prestanda. En exempel-impementation av en bra skriven PSR-0 autoloader kan du se på https://gist.github.com/221634 . Den är fullt produktionsduglig och är skriven av några av de främsta PHP-profilerna (både Zends och Symfonys huvudutvecklare finns representerade t ex). Angående din kommentar om require_once så blir den inte alls gällande när du har en väl skriven autoloader. Det finns då längre ingen anledning att köra _once-funktionerna då andra användandet av klassen inte kommer försöka inkludera filen igen. Så en _once ger dig då ENDAST dubbla stat calls helt utan fördelar.
__________________
eldefors.com - Personlig (teknik)-blogg |
||
![]() |
![]() |
![]() |
#3 | |||
|
||||
Mycket flitig postare
|
Appropå prestanda, i de flesta fall är ju OOP att föredra, men i de fall där man skall processa mkt data kan OOP ge en märkbar prestandaförsämring. För några år sedan gjorde jag tester mellan vanlig kod och OOP kod. I koden nedan krypteras en 1k-sträng 1k gånger, dvs totalt 1 megabyte data. OOP-varianten ger en enorm prestandaförsämring, flera hundra procent, testade även nu på en obelastad server med följande resultat:
Kod:
Non OOP Result: 1.6096091270447 seconds OOP Result: 4.6408619880676 seconds Kod:
<?php // Create 1k string $initString=""; while (strlen($initString)<1024) $initString .="abcdef0123456789"; /* --------------------------------------------------- Non-OOP test --------------------------------------------------- */ $time_start = microtime(true); for ($i=0; $i<1024; $i++) { Non_OOP_test($initString,false); } $time_end = microtime(true); $time = ($time_end - $time_start); echo "<pre>Non OOP Result: $time seconds\n"; // Verification $encrypted = Non_OOP_test($initString,true); $decrypted = Non_OOP_test($encrypted,true); echo "Encrypted: $encrypted\n"; echo "Decrypted: $decrypted\n</pre>"; /* --------------------------------------------------- OOP test --------------------------------------------------- */ $time_start = microtime(true); for ($i=0; $i<1024; $i++) { OOP_test($initString,false); } $time_end = microtime(true); $time = ($time_end - $time_start); echo "<pre>OOP Result: $time seconds\n"; // Verification $encrypted = OOP_test($initString,true); $decrypted = OOP_test($encrypted,true); echo "Encrypted: $encrypted\n"; echo "Decrypted: $decrypted\n</pre>"; function OOP_test($instr, $return) { $arc4 = new ARC4(); $arc4->init("pAsSwOrD"); $arc4->process($instr,1024); if ($return) return $instr; } function Non_OOP_test($instr, $return) { global $x, $y, $state, $statebackup; $x = $y = 0; $state = array(); $statebackup =array(); arc4_init("pAsSwOrD"); arc4_process($instr,1024); if ($return) return $instr; } //------------------------------------------------------------------------------- // ARC4 Encryption class in PHP //-------------------------------------------------------------------------------- class ARC4 { private $state = array(); private $statebackup = array (); private $x = 0; private $y = 0; function init($key) // init key schedule { $len= strlen($key); for ($this->x = 0; $this->x < 256; $this->x++) $this->state[$this->x] = $this->x; $this->y = 0; for ($this->x = 0; $this->x < 256; $this->x++) { $this->y = ($this->y + $this->state[$this->x] + ord($key[$this->x % $len])) % 256; $temp = $this->state[$this->x]; $this->state[$this->x] = $this->state[$this->y]; $this->state[$this->y] = $temp; } // Skip the first 256 bytes to avoid some weakness $temp=""; for ($this->x = 0; $this->x < 256; $this->x++) $temp[$this->x]=chr($this->x); $this->process($temp,256); $this->x = $this->y = 0; $this->statebackup=$this->state; } function process(&$instr, $len) // encrypt/decrypt raw ascii { for ($c= 0; $c < $len; $c++) { $this->x = ($this->x + 1) % 256; $this->y = ($this->y + $this->state[$this->x]) % 256; $temp = $this->state[$this->x]; $this->state[$this->x] = $this->state[$this->y]; $this->state[$this->y] = $temp; $instr[$c] = chr(ord($instr[$c]) ^ $this->state[($this->state[$this->x] + $this->state[$this->y]) % 256]); } } } //-------------------------------------------------------------------------------------------------- function arc4_init($key) // init key schedule { global $x, $y, $state, $statebackup; $len= strlen($key); for ($x = 0; $x < 256; $x++) $state[$x] = $x; $y = 0; for ($x = 0; $x < 256; $x++) { $y = ($y + $state[$x] + ord($key[$x % $len])) % 256; $temp = $state[$x]; $state[$x] = $state[$y]; $state[$y] = $temp; } // Skip the first 256 bytes to avoid some weakness $temp=""; for ($x = 0; $x < 256; $x++) $temp[$x]=chr($x); arc4_process($temp,256); $x = $y = 0; $statebackup=$state; } function arc4_process(&$instr, $len) // encrypt/decrypt raw ascii { global $x,$y,$state; for ($c= 0; $c < $len; $c++) { $x = ($x + 1) % 256; $y = ($y + $state[$x]) % 256; $temp = $state[$x]; $state[$x] = $state[$y]; $state[$y] = $temp; $instr[$c] = chr(ord($instr[$c]) ^ $state[($state[$x] + $state[$y]) % 256]); } } ?> |
|||
![]() |
![]() |
![]() |
#4 | ||
|
|||
Klarade millennium-buggen
|
Jag testkörde SimonPs kod (på en betydligt långsammare maskin) och fick följande resultat:
Kod:
Non OOP Result: 2.6286079883575 seconds OOP Result: 5.3388919830322 seconds Sen har det alltid varit så att OOP körningar tar något längre tid eftersom det är mer att göra för systemet. Det är inte av prestandaskäl man väljer OOP i stället för imperativa språk, det är för att kunna hantera komplexitet på ett bättre sätt och minska risken för buggar, återanvändbarhet av tidigare kod, samt därmed kortare utvecklingstid. Maskiner blir ständigt snabbare så hastigheten är inte det avgörande i de flesta fall. PHP ger i sig prestandaförluster i och med att det dessutom är interpreterande och inte kompilerande. Är hastigheten en kritisk faktor så väljer man ett annat språk. Senast redigerad av Conny Westh den 2012-09-15 klockan 12:58 |
||
![]() |
![]() |
![]() |
#5 | |||
|
||||
Mycket flitig postare
|
Citat:
|
|||
![]() |
![]() |
![]() |
#6 | ||
|
|||
Medlem
|
Citat:
Vad gäller detta test, intressant vore se vilken skillnad det blir om man använder statisk metoder istället för instansiering. Förmodligen lite mindre minnesutnyttjande, vilket ju blir lite mer "rättvist" eftersom oop gör lite mer än funktionella koden om den instansierar |
||
![]() |
![]() |
![]() |
#7 | ||
|
|||
Klarade millennium-buggen
|
Citat:
Stark typning kan i många programspråk ge 50-100 gånger prestandaförbättring även i en interpreterande eller semikompilerad miljö. Dock helt riktigt att statiska metoder ger betydande prestandaförbättring i OOP-sammanhang jämfört med instansiering, men det beror på vilket problem man ska lösa om man kan använda det eller inte. Senast redigerad av Conny Westh den 2012-09-16 klockan 23:28 |
||
![]() |
![]() |
![]() |
#8 | ||
|
|||
Medlem
|
Med bytecode caches så kompileras och parsas koden endast vid första request. Så den overhead som JIT kompilering ger per default i PHP kan alltså undvikas.
Jag invände mot att du sa : om hastighet är en kritisk faktor så väljer man ett annat språk. Om man gör extremt stora beräkningar m.m i kod så är det klokt att inte använda php, t.ex motsvarande detta performance test i denna tråd. Där skulle asp.net eller cgi/c++ "vinna". Det jag menar är att generellt väljer man inte bort php pga sämre prestanda i webblösningar. |
||
![]() |
![]() |
![]() |
#9 | ||
|
|||
Administratör
|
Citat:
Annars håller jag med dig om att man generellt sätt inte väljer bort PHP av prestandaskäl. Förutom vid väldigt speciella applikations-typer, t ex en chat eller annan websockets-hantering - och då är inte anledningen exekveringstiden.
__________________
eldefors.com - Personlig (teknik)-blogg |
||
![]() |
![]() |
Svara |
|
|