Genel PHP mayınla [kapalı]

24 Cevap php

Ne sürprizler diğer insanların PHP web uygulamaları yazma ile bulduk? Orada zaman derleme sınıfı miras ile bilinen ve sabit olması sorun ama ben bir kaç başkalarının bilmek ve dilin üst yakaladım yıllardan bir listesini deneyin ve inşa etmek istedim.

Not:

Ben bu yüzden PHP iş bu soru Ben birlikte çalıştığım her dil olarak bir dil olarak PHP üzerinde büstü anlamına değil, benim faturaları ödeyen bir Sr PHP5 geliştirici olarak çeşitli görevlerde ettik bazı iyi çok iyi bilinen tanınmış ya sürprizler var .

24 Cevap

Ben bu sayar emin değilim, ama PHP komut derlemek için ihtiyaç çok büyük bir performans konudur. Herhangi bir ciddi PHP projesinde size APC, eAccelerator, PHP Accelerator gibi derleyici önbellek çeşit, ya Zend Platform (ticari) gerekir.

Recursive references leak memory

Iki nesneleri oluşturmak ve birbirlerinin özelliklerini içinde saklarsanız, çöp toplayıcı onlara dokunmak asla:

$a = new stdClass;
$b = new stdClass;
$a->b = $b;
$b->a = $a;

Büyük bir sınıf genellikle ana sınıf saklayan bir küçük yardımcı nesne oluşturduğunda bunu yapmak aslında oldukça kolaydır:

// GC will never clean up any instance of Big.
class Big {
  function __construct() {
    $this->helper = new LittleHelper($this);
  }
}
class LittleHelper {
  function __construct(Big $big) {
    $this->big = $big;
  }
}

Sürece PHP kısa hızlı sayfa istekleri hedef olarak, bu sorunu gidermek için olası değildir. Bu PHP uzun bir ömre sahip cinleri veya diğer uygulamalar için bağlı olması anlamına gelir.

aşırı kullanıldığında Require_once ve include_once genellikle büyük performans katiller neden olabilir. Senin / dahil bir sınıf tutan bir dosya ihtiyacınız varsa ... Bunun gibi bir model bazı ciddi işleme zamandan tasarruf edebilirsiniz.

class_exists("myFoo") or require("myFoo.someClass.php");

Update: This is still a issue - http://www.techyouruniverse.com/software/php-performance-tip-require-versus-require_once

Update: Read the selected answer for the following question: http://stackoverflow.com/questions/135373/would-performance-suffer-using-autoload-in-php-and-searching-for-the-class-file If implemented along these lines, you pretty much minimize as best as possible the penalties for file include/requires.

NULL ve "0" dizesi Php saf kötülük vardır

if ("0" == false) //true
if ("0" == NULL)  //true
if ("0" == "NULL")//true
  • foreach () sessizce arka planda dizi kopyalama ve kopya yoluyla yineleme edilir. Eğer büyük bir dizi varsa, bu performansı düşer. Bu gibi durumlarda, foreach tarafından referans seçenekleri () php5 için yeni olduğunu ya da () döngü için kullanın.

  • Kimlik vs eşitlik (==) (===) farkında olun.

  • Isset () neyin boş () vs neyin farkında olun.


Biraz daha zaman var olduğunu şimdi daha kara mayını:

  • Eşitlik için yüzer karşılaştırmak etmeyin. PHP matlab değildir ve sadece hassas kayan nokta aritmetiği için tasarlanmış değildir. Bunu dene:
if (0.1 + 0.2 == 0.3)
  echo "equal";
else
  echo "nope"; // <-- ding ding
  • Benzer şekilde, octals unutma! Başında sıfır w / bir int bir sekizlik olarak atıldı.
if (0111 == 111)
  echo "equal";
else
  echo "nope"; // <-- ding ding

Bu tür bariz aslında sonra oldu ama iyi bilinen bir yakaladım foreachta kullanıldığında kapsam ve referansları ile ilgisi yoktur.

foreach($myArray as &$element){
   //do something to the element here... maybe trim or something more complicated
}
//Multiple lines or immediately after the loop

$element = $foobar;

Yukarıdaki foreachta referans geçerli bağlam kapsamında hala çünkü dizideki son hücre artık $ filanca haline gelmiştir.

__autoload() Son zamanlarda benim için önemli bir mayın olduğunu kanıtladı. Bizim eski bazı kod ve kütüphaneler class_exists() kullanmak ve bu şekilde yüklenecek anlamına asla özdevinimli_yükle sınıfları çalışır. Ölümcül hataları ve uyarıları sürü. class_exists() Eğer autoload varsa hala kullanılabilir, ancak ikinci parametre (yeni PHP 5.2.0 'dan beri) false olarak ayarlanmalıdır

Farkında olmak değil operator precedence bazı sorunlara neden olabilir:

if ($foo = getSomeValue() && $bar) {
    // …
}
// equals
if ($foo = (getSomeValue() && $bar)) {
    // …
}

@ hata susturucu daima kaçınılmalıdır.

Örnek:

// Don't let the user see an error if this unimportant header file is missing:
@include 'header.inc.php';

Yukarıdaki kod ile, header.inc.php kodun herhangi bir ya header.inc.php çağrılan fonksiyonların herhangi birinde hatalar hakkında bilmek ve bir Ölümcül Hata bir yerde varsa, asla web sayfası hata ne olduğunu öğrenmek için hiçbir şekilde durur.

Ben insanların kurbanı gördüm büyük yakaladım (php ve diğer dillerde) hassas olduğunu.

Eğer biraz eğlenmek> = bir bütünün herhangi bir şamandıra karşılaştırmak ve beklenen sonuç almak kaç kere öğrenmek istiyorum.

Bu PHP içinde para ile çalışan ve bir tam sayıya yuvarlama izin vermez karşılaştırmalara dayalı mantık kararlar çalışan birçok insanın düşüşünü olmuştur.

Örneğin - Kumaş

Kumaş 1 yarda ya da 1 yarı bahçesinde hem de kumaşın kalan kesin ölçüm envanterinin muhafaza birimi satılmaktadır.

Bu sistem bütün sayılarla ifade edilmez ve bunun yerine kayan nokta olarak ifade edilir ise inanılmaz derecede sert ve katı kararlarını yapmak için yapacaktır.

Yapabileceğiniz en iyi şey kumaş 300 yds varsa, 600 (600 yarda yarım adet) bir envanter olurdu örneğin, 1 olarak 1 buçuk bahçesinde bildirmektir.

Her neyse, benim gotcha şu - Vadesi hassasiyet anlayış değil programlama 4 ay refactor zaman ....

Numeric strings automatically converted to integers

Yani PHP çok çirkin ve en karanlık kesmek tarafından bulunuyor. Tüm basamaklı bir dize var her zaman bazı durumlarda tamsayı sanki, otomatik tedavi alır.

php > var_dump("0" == "00");
bool(true)

Bu alabilirsiniz gerçekten kötü garabeti lider PHP'nin "ilişkilendirilebilir dizilerle" ile birlikte burada $a == $b anlamına gelmez, o $arr[$a] == $arr[$b];

php > var_dump(array('00'=>'str(zerozero)', '0'=>'str(zero)'));
array(2) {
  ["00"]=>
  string(13) "str(zerozero)"
  [0]=>
  string(9) "str(zero)"
}

Benim favori PHP yakaladım:

Bu şunlardır düşünün:

# ... lots of code ...
$i = 42;
# ... more code ...

Sonra bu yere dahil kullanın:

for($i = 0; $i < 10; $i++){
    # ...
    include 'that_other_file.php';
}

Then try to guess how many times the loop runs. Yup, once. Lexical scoping (and proper dynamic scoping) are both solved problems. But not in PHP.

Eğer akıllı mantıksal operatörleri ile dillere kullanılan iseniz, sizin gibi şeyler yapmaya çalışacağız:

$iShouldTalkTo = $thisObj || $thatObj;

PHP, $iShouldTalkTo şimdi bir mantıksal değerdir. Sen yazmak zorunda konum:

$iShouldTalkTo = $thisObj ? $thisObj : $thatObj;

PHP erken tasarım kararları yetkili olanları çökmüş karşılığında beceriksiz programcılar ellerini tutmak için çalıştı nasıl tüm örnekler dışında, bu beni en çok rahatsız biri olabilir.

switch() yapı Derin beyin hasarı doludur. Bu düşünün:

switch($someVal) {
case true  :
    doSomething();
    break;
case 20    :
    doSomethingElse();
    break;
}

'Vaka gerçek' $ SOMEVAL ve all gerçek olgu absorbe çünkü doSomethingElse(), denilen asla çıkıyor.

Belki de haklı olduğunu düşünüyorum? Peki, bu bir deneyin:

for($ix = 0; $ix < 10; $ix++) {
    switch($ix) {
    case 3  :
        continue;
    default :
        echo ':';
    }
    echo $ix;
}

Çıktısı ne olduğunu tahmin? Olmalıdır: 0:1:2:4:5:6:7:8:9, değil mi? Hayır, bu: 0:1:23:4:5:6:7:8:9. Yani, o ignores the semantics continue deyimi ve bir break gibi davranır onu bir.

Kötü bir biri tamamen bir dizi, bir sözlük ve bir liste melez başarısız olan PHP's "associative arrays" kavramı vardır. PHP'nin yazarlar diziler 'artı operatörü ve array_merge fonksiyonunun bize böyle farklı bir davranış garabeti neden her durumda, nasıl davranması gerektiği konusunda emin görünüyor.

php > $a = array(1=>'one');
php > $b = array(2=>'two');
php > var_dump($a+$b); /* plus preserves original keys */
array(2) {
  [1]=>
  string(3) "one"
  [2]=>
  string(3) "two"
}
php > var_dump(array_merge($a,$b)); /* array_merge reindexes numeric keys */
array(2) {
  [0]=>
  string(3) "one"
  [1]=>
  string(3) "two"
}


php > $a = array(1=>'one');
php > $b = array(1=>'another one');
php > var_dump($a+$b);  /* plus ignores duplicate keys, keeping the first value */
array(1) {
  [1]=>
  string(3) "one"
}
php > var_dump(array_merge($a,$b)); /* array_merge just adds them all, reindexing */
array(2) {
  [0]=>
  string(3) "one"
  [1]=>
  string(11) "another one"
}

php > $a = array(1,2,3);
php > $b = array(4,5,6);
/* non-associative arrays are really associative arrays with numeric keys… */
php > var_dump($a+$b);  /* … so plus doesn’t work as you’d normally expect */
array(3) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
}
php > var_dump(array_merge($a,$b));  /* you should use array_merge instead */
array(6) {
  [0]=>
  int(1)
  [1]=>
  int(2)
  [2]=>
  int(3)
  [3]=>
  int(4)
  [4]=>
  int(5)
  [5]=>
  int(6)
}

Toplam bellek PHP çalışırken. Birçok büyük projeler sadece tüm sınıf dosyaları içerir ve bunları gerektiğinde bunları kullanmak. Bu PHP her çalıştırmak için kullanması gereken toplam hafızasına ekler.

Ayrıca, bu kolayca bellek kullanımını iki katına çıkabilir gibi Çerçeveler veya çerçevelerde kullanarak projeler.

Yani, sınıf dosyalarının bir koşullu yükleme istihdam şey kullandığınız olmadığını yüklediniz

PHP uygulamalar ile performans sorunları genellikle aşağıdakilerden biri gibidir:

  • File system access - reading and writing to disk
    • APC, eAccelerator, vb gelmek içinde bu, onlar bellekte çözümlü PHP dosyaları önbelleğe alarak dosya sistemi erişimi azaltmak
  • Veritabanı - Yavaş sorgular, büyük veri setleri
  • Ağ I / O - dış kaynaklara erişimini

PHP (veya herhangi bir dilde yazılmış herhangi bir web uygulaması) ile performans sorunları çalıştırmak için oldukça nadirdir. Yukarıdaki sorunlar genellikle kod yürütülmesine daha yavaş büyüklüklerdir.

Her zaman olduğu gibi, sizin kod profil!

PHP başka bir hatadır, genellikle diğer dillerde gelen ancak insanlar bu hatayı görmüştüm.

<?php
/**
 * regular
 */
echo (true && true); // 1
echo (true && false); // nothing

echo (true || false); // 1
echo (false || false); // nothing

echo (true xor false); // 1
echo (false xor false); // nothing

/**
 * bitwise
 */
echo (true & true); // 1
echo (true & false); // 0

echo (true | false); // 1
echo (false | false); // 0

echo (true ^ false); // 1
echo (false ^ false); // 0
?>

If / else dalları için derleyici mesajları elde değil:

if( $foo )
{
  some_function();
}
else
{
  non_existing_function();   // oops!
}

PHP $foo yanlış bir durum girmek kadar non_existing_function yok söz olmaz.


Ayarlamak için unutmak:

error_reporting( E_ALL );

Yani bildirimler zaman hata ayıklama harcama, yakalanmış değil:

  • mevcut olmayan değişkenler
  • Geçersiz nesne özellikleri
  • geçersiz dizi anahtarları

Onları kaçan olmadan, farklı "tür" / kaynaklar birlikte dizeleri yapıştırılıyor:

// missing mysql_real_escape_string() or an int cast !
$sql = "SELECT * FROM persons WHERE id=$id";

// missing htmlentities() and urlencode() !
$html = "<a href='?page=$id'>$text</a>";  

http://stackoverflow.com/questions/3117604/why-is-calling-a-function-such-as-strlen-count-etc-on-a-referenced-value-so-sl/3117608 başı olarak

Eğer referans bir işleve bir değişken geçmek, ve sonra bunun üzerine bir işlevi çağırmak, o incredibly yavaş.

Işlev çağrısı ve değişken üzerinde size döngü büyükse o değişken değeri tarafından geçirilir ise daha yavaş birçok büyüklük olabilir.

Örnek:

<?php
function TestCount(&$aArray)
{
    $aArray = range(0, 100000);
    $fStartTime = microtime(true);

    for ($iIter = 0; $iIter < 1000; $iIter++)
    {
        $iCount = count($aArray);
    }

    $fTaken = microtime(true) - $fStartTime;

    print "took $fTaken seconds\n";
}

$aArray = array();
TestCount($aArray);
?>

Bu sürekli (PHP 5.3) benim makinede çalıştırmak için yaklaşık 20 saniye sürer.

Ben değere geçmek için işlevini değiştirmek Ama eğer (yani function TestCount($aArray) yerine function TestCount(&$aArray)), daha sonra da yaklaşık 2ms çalışır - literally 10,000 times faster!

Böyle strlen gibi iki yerleşik işlevleri ve kullanıcı tanımlı işlevler için - aynı değere geçer herhangi bir fonksiyon için de geçerlidir.

Bu benim daha önce habersiz oldukça korkutucu Tarpit olduğunu!

Döngü içinde geçici bir yerel değişkeni kullanın, ve sonunda referans değişkene kopyalamak - Neyse ki birçok durumda uygulanabilir basit bir çözüm var.

Sadece bir sürpriz düşündüm. bir diziye bir geri uygulandığı array_map, ciddi bir performans katil. Ben niçin tamamen emin değilim, ama döngüler için yazma mekanizması PHP'nin kopya ile ilgisi olduğunu düşünüyorum.

başından bir kodu bu tür hata ayıklama çok zaman geçirdim olabilir:

$a = 1;
echo $a;      # 1
echo "$a";    # 1
echo '$a';    # $a

lanet tırnak! çok sinir bozucu: (

Typecasting and triple equal

Eğer iki farklı veri türleri üzerinde işlem yaparken genellikle, dillerin çoğunda bir istisna olsun ya da bunlardan biri daha genel birine döküm alır. PHP hariç dilinde, dize tamsayı daha genel olarak kabul edilir. Sadece PHP var:

php > var_dump('nada' == 0);
bool(true)

Bu PHP ile başa çıkmak için üçlü eşitlik operatörü tanıttı. Hangi değerler aynı tip ve aynı değerde ise tanımı gereği true döndürür. Yukarıdaki örneğin çalışır:

php > var_dump('nada' === 0);
bool(false)

Ama aynı zamanda aslında like değerleri eşit olması için ne zaman oldukça çirkin davranır.

php > var_dump(0.0 === 0);
bool(false)

Başka dilden tecrübesi ile PHP ile çalışmak için geliyorlar, bu sorunları var uğrarsınız.

$x = array();
$x == null ? "true": "false";

Çıkış "doğru" dur.

$x = array("foo");
$x == null ? "true": "false";

Çıkış "yanlış" olduğunu;