"Sıkı standartlar: Yalnızca değişkenler referans olarak iletilmelidir" hata mesajı


81
$el = array_shift($instance->find(..))

Yukarıdaki kod bir şekilde katı standartlar uyarısını bildirir, ancak bu:

function get_arr(){
    return array(1, 2);
}
$el = array_shift(get_arr());

Peki uyarıyı ne zaman rapor edecek?


1
$ Örnek-> find (..) ne döndürür?
Silver Light


Ben örnekler (veya mantık) 2 örnek (beri söz konusu yanlış bir yol yuvarlak, olabileceğini düşünüyorum get_arr()fonksiyonu) vermez sıkı standartlar haber (PHP 5.2 ve PHP 5.5 test) üretirler.
MrWhite

Yanıtlar:


93

Aşağıdaki kodu göz önünde bulundurun:

error_reporting(E_STRICT);
class test {
    function test_arr(&$a) {
        var_dump($a);
    }
    function get_arr() {
        return array(1, 2);
    }
}

$t = new test;
$t->test_arr($t->get_arr());

Bu, aşağıdaki çıktıyı üretecektir:

Strict Standards: Only variables should be passed by reference in `test.php` on line 14
array(2) {
  [0]=>
  int(1)
  [1]=>
  int(2)
}

Sebep? test::get_arr()Yöntem değişken değildir ve sıkı modunda bu bir uyarı üretecektir. get_arr()Yöntem bir dizi değeri döndürdüğünden , bu davranış son derece sezgisel değildir .

Katı modda bu hatayı aşmak için, ya yöntemin imzasını bir referans kullanmayacak şekilde değiştirin:

function test_arr($a) {
    var_dump($a);
}

İmzanızı değiştiremeyeceğiniz için array_shiftbir ara değişken de kullanabilirsiniz:

$inter = get_arr();
$el = array_shift($inter);

7
@ user198729: Ben de bir açıklama veya düzeltme arıyordum ve ilk öğe için current () kullanabileceğinizi öğrendim. Ne yazık ki end (), "dahili işaretçiyi son öğeye ilerlettiğinden" sonuncusu için çalışmaz. current (array_reverse (somefunction ())) çalışır (evet, saçma)
MSpreij

1
Kullanmak current, dizi göstericisinin ilk öğede olduğu varsayımını yapar. Çoğu durumda geçerli bir varsayım olabilir, ancak dikkat edilmesi gereken biri.
cmbuckley

1
@leepowers Tabii ki, o zaman array_shift()bir referansın değiştirilmesini beklemesiyle aynı sorun olurdu :-)
cmbuckley

1
@ user198729 $intermediateFazladan bir çift parantez kullanarak değeri önleyebilirsiniz . $el = array_shift( ( get_arr() ) );. Bkz stackoverflow.com/questions/9848295/...
Chloe

1
@Chloe Bu, kodu basit tutmak için gördüğüm en mükemmel çözüm !! Teşekkür ederim!
hargobind

7

$instance->find() bir değişkene başvuru döndürür.

Bu referansı, önce bir değişkene kaydetmeden, bir işleve argüman olarak kullanmaya çalıştığınızda raporu alırsınız.

Bu, bellek sızıntılarını önlemeye yardımcı olur ve muhtemelen sonraki PHP sürümlerinde bir hata haline gelecektir.

İkinci kod bloğunuz şöyle yazarsa bir hata atar ( &işlev imzasına dikkat edin ):

function &get_arr(){
    return array(1, 2);
}
$el = array_shift(get_arr());

Yani hızlı (ve o kadar da hoş olmayan) bir düzeltme şu şekilde olacaktır:

$el = array_shift($tmp = $instance->find(..));

Temel olarak, önce geçici bir değişkene atama yaparsınız ve değişkeni argüman olarak gönderirsiniz.


Şimdi çalışmalı (kontrol et). Referansı geri döndürmek için onu dönüş ifadesinde değil, yöntem imzasında bildirmeniz gerekir (benim hatam).
Sagi

Hayır, imzayı değiştiremiyorum. @ Pygorex1'in ara değişkeni bunu çözebilir, ama gereksiz görünüyor, değil mi?
user198729

İmzayı değiştiremeyeceğini biliyorum, sadece nasıl olduğunu açıkladım. Sen sahip geçici (= orta) değişken kullanmak, ancak aynı çizgide yapabilirsiniz. İkinci kod parçama bakın.
Sagi

4
İkinci pasajınızı denedim, çalışmıyor. Yalnızca ayrı bir satırda çalışıyor
user198729

3
Aslında. Bir atama , atanan değeri döndürür . array_shift($tmp = $instance->find(..))atar değeri $instance->find(..)için $tmpve daha sonra geçen atama değeri için array_shift()- geçirmeden aynı şey değildir $tmpkendisi, bu nedenle daha iyi bir atama olmadan orijinal durumuna daha uzundur.
phils

6

Hatanın nedeni dahili PHP programlama veri yapıları işlevinin, array_shift () [php.net/end] kullanılmasıdır.

İşlev, parametre olarak bir diziyi alır. array_shift()Kılavuzda prototipinde bir "ve işareti" belirtilmesine rağmen , bu işlevin genişletilmiş tanımını takip eden herhangi bir uyarıcı belge veya parametrenin aslında referansla aktarıldığına dair açık bir açıklama yoktur.

Belki de bu / anlaşıldı /. Ancak anlamadığım için hatanın nedenini tespit etmem zor oldu.

Kodu yeniden üretin:

function get_arr()
{
    return array(1, 2);
}
$array = get_arr();
$el = array_shift($array);

3

Bu kod:

$monthly_index = array_shift(unpack('H*', date('m/Y')));

Değiştirilmesi gerekiyor:

$date_time = date('m/Y');
$unpack = unpack('H*', $date_time);
array_shift($unpack);


0

Pekala, bunun gibi bariz durumlarda, PHP'ye mesajları bastırmasını her zaman işlevin önünde "@" kullanarak söyleyebilirsiniz.

$monthly_index = @array_shift(unpack('H*', date('m/Y')));

Tüm hataları bu şekilde bastırmak en iyi programlama uygulamalarından biri olmayabilir , ancak bazı durumlarda (bunun gibi) kullanışlı ve kabul edilebilir.

Sonuç olarak, eminim arkadaşınız 'sistem yöneticisi' daha az kirlilikten memnun kalacaktır error.log.


Bu cevaba kimin olumsuz oy verdiğini bilmiyorum, ancak sunulan çözüm ÇALIŞIYOR ve PHP standart bir tekniktir. Gerçekten hayal kırıklığı ... Bir dahaki sefere artık bir soruyu yanıtlayamayabilirim ... :(
Julio Marchi

5
Hata mesajını bastırmanın koddaki sorunu çözmediği için olduğunu varsayardım. Gelecekteki bir PHP sürümünde bu tür bir hata E_STRICT'den E_ERROR'a değiştiğinde ve kodunuz şimdi çalışmadığında ve ayrıca herhangi bir hata / çıktı üretmediğinde ne yapacaksınız?
Luke

@TinoDidriksen, özellikle yeni nesiller için bazı "kötü alışkanlıklara" karşı tavsiyelerde bulunmanın nedenlerini anlıyor ve kabul ediyorum. Bununla birlikte, kullanımı güvenli ve önerilen bağlama uygun olduğunda (ve eğer) kullanılacak bir kaynak mevcuttur. Hata bastırıcı "@" kaldırılacak olsaydı, dilin kendisinden kaldırılırdı. "Eval" ile aynı (kötü olabilir, ancak amaçları vardır). Karşı olduğum şey bazı kaynakların kullanılması değil, bir tavsiyenin genelleştirilmesidir. Önerilen vakaya özel olarak, hata ayıklama amacıyla bile kullanmanın herhangi bir zararı olmaz.
Julio Marchi
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.