Bir İşlevde Varsayılan Bağımsız Değişkenleri Kullanma


177

PHP işlevleri için varsayılan değerler hakkında kafam karıştı. Diyelim ki böyle bir fonksiyon var:

function foo($blah, $x = "some value", $y = "some other value") {
    // code here!
}

$ X için varsayılan bağımsız değişkeni kullanmak ve $ y için farklı bir bağımsız değişken ayarlamak istersem ne olur?

Farklı yollarla denemeler yapıyorum ve daha da kafam karışıyor. Örneğin, şu ikisini denedim:

foo("blah", null, "test");
foo("blah", "", "test");

Ancak bunların her ikisi de $ x için uygun bir varsayılan argüman ile sonuçlanmaz. Ayrıca değişken adıyla ayarlamaya çalıştım.

foo("blah", $x, $y = "test");   

Böyle bir şeyin tam olarak çalışmasını bekliyordum. Ama beklediğim gibi çalışmıyor. Ne yaparsam yapayım, işlevi her başlattığımda zaten varsayılan argümanları yazmak zorunda kalacağım. Ve bariz bir şeyi kaçırmalıyım.


68
Muhtemelen hiçbir şey kaçırmıyorsunuz, PHP geliştiricileri muhtemelen bunu kaçırdı.
Matti Virkkunen

Bu ilginç bir soru. Aslında, orijinaline neyin bağlı olduğundan emin olmadığımda diğer programcılar tarafından miras alınan işlevleri genişletmek için varsayılan argümanları kullandığım için bunu belirttiğiniz gibi yapmam gerekmedi. Bir cevap merak ediyorum.
Kai Qing

3
Bir süredir gördüğüm en iyi sorulardan biri! Hiçbir şey geçmeyi denedin mi? foo("blah", , "test");?
Madara'nın Hayaleti

2
Kural, varsayılan bağımsız değişkenlerin yalnızca bağımsız değişkenleri izleyebilmesidir. Yani foo ("blah") ve x, y varsayılan olabilir veya foo ("Blah", "xyz") ve y varsayılan değerdir.
Fare Yiyecek

1
Beklenen davranış. "Varsayılan bağımsız değişken değerleri" bölümüne bakın: php.net/manual/tr/functions.arguments.php - null değeri ve boş dize şu işleve gerçek bağımsız değişkenler olarak kabul edilir
jmdavalos

Yanıtlar:


164

İşlev bildirimini aşağıdaki gibi değiştirmeyi öneriyorum, böylece istediğinizi yapabilirsiniz:

function foo($blah, $x = null, $y = null) {
    if (null === $x) {
        $x = "some value";
    }

    if (null === $y) {
        $y = "some other value";
    }

    code here!

}

Bu şekilde, foo('blah', null, 'non-default y value');ikinci parametrenin $xhala varsayılan değerini aldığı yerlerde istediğiniz gibi bir arama yapabilir ve istediğiniz gibi çalışmasını sağlayabilirsiniz .

Bu yöntemle, boş bir değer iletilmesi, bir parametrenin ardından gelen bir parametrenin varsayılan değerini geçersiz kılmak istediğinizde bir parametre için varsayılan değerin olmasını istediğiniz anlamına gelir.

Diğer cevaplarda belirtildiği gibi,

varsayılan parametreler yalnızca işleve son argümanlar olarak çalışır. İşlev tanımındaki varsayılan değerleri bildirmek isterseniz, bir parametreyi atlamanın ve ardından bir parametreyi geçersiz kılmanın bir yolu yoktur.

Değişken sayıda parametreyi ve değişken tipteki parametreleri kabul edebilecek bir yöntemim varsa, genellikle Ryan P tarafından gösterilen cevaba benzer işlevi beyan ederim.

İşte başka bir örnek (bu, sorunuza cevap vermiyor, ancak umarım bilgilendirici:

public function __construct($params = null)
{
    if ($params instanceof SOMETHING) {
        // single parameter, of object type SOMETHING
    } else if (is_string($params)) {
        // single argument given as string
    } else if (is_array($params)) {
        // params could be an array of properties like array('x' => 'x1', 'y' => 'y1')
    } else if (func_num_args() == 3) {
        $args = func_get_args();

        // 3 parameters passed
    } else if (func_num_args() == 5) {
        $args = func_get_args();
        // 5 parameters passed
    } else {
        throw new InvalidArgumentException("Could not figure out parameters!");
    }
}

Neden $ x = isset ($ x) değil? $ x: 'varsayılan değer'; ?
zloctb

@zloctb Bu temiz ve okunabilir bir boş denetimdir. Görünüşe göre geliştirici tercihi. Ya $ x = isset ($ x)? $ x: 'varsayılan değer'; veya $ x = is_null ($ x)? 'varsayılan değer': $ x; hem de bu çözüm işe yarayacaktı. Okunabilirlik ve bakım için tercih edilen bir seçimdir.
DeveloperWeeks

9
Sadece gelecekteki okuyucular için netlik. İlk çözüm null, parametreye gerçek bir değer atamayı açıkça imkansız hale getirir , çünkü her seferinde varsayılan değer atayacaktır. Gerçekte null istediğinizde başka bir özel değeriniz olsa bile (örneğin, $ x == "use_null" $ x = null olduğunda), o zaman parametresi (bu durumda, "use_null" dizesi). Bu nedenle, varsayılan değeri kullanmak istediğinizde (ve nullgeçerli bir seçenek olmak istediğinizde) benzersiz, asla arzu edilmeyen bir "anahtar" kullandığınızdan emin olun
DiegoDD

37

İsteğe bağlı bağımsız değişkenler yalnızca bir işlev çağrısının sonunda çalışır. $ X belirtmeden işlevinizde $ y için bir değer belirtmenin bir yolu yoktur. Bazı diller bunu adlandırılmış parametrelerle (örneğin VB / C #) destekler, ancak PHP'yi desteklemez.

Parametreler için bağımsız değişkenler yerine ilişkilendirilebilir bir dizi kullanırsanız bunu taklit edebilirsiniz - ör.

function foo(array $args = array()) {
    $x = !isset($args['x']) ? 'default x value' : $args['x'];
    $y = !isset($args['y']) ? 'default y value' : $args['y'];

    ...
}

Sonra işlevi şöyle çağırın:

foo(array('y' => 'my value'));

1
Durumunuz isset($args['x']), şu anda boş bir dize, boş bir dizi veya falsevarsayılan değerle değiştirileceği için gerçekten olmalıdır .
Tim Cooper

@TimCooper lol '=== null' olması gerektiği ilk yorumunuza göre değişmeye gittim, gidip onun yerine isset kullanmak için cevabımı değiştirdim, sonra da yorumunuzu değiştirdiğinizi görmek için geri döndüm. : D
Ryan P

Ah, canım! Bunu hiç sevmiyorum ... Oh, her şeye sahip olamazsın. Sanırım varsayılan argümanlarımın sırasına biraz daha düşünmek zorunda kalacağım. Teşekkürler!
renosis

Ne yazık ki, bu cevapla null atayamazsınız. Bu daha iyi bir seçenektir: $x = !array_key_exists('x',$args) ? 'default x value' : $args['x'];
Frank Forte

20

Aslında mümkün:

foo( 'blah', (new ReflectionFunction('foo'))->getParameters()[1]->getDefaultValue(), 'test');

Bunu yapmak isteyip istemediğiniz başka bir hikaye :)


GÜNCELLEME:

Bu çözümden kaçınmanın nedenleri:

  • (tartışmasız) çirkin
  • bariz bir yükü var.
  • diğer cevapların kanıtı olarak, alternatifler var

Ancak aslında aşağıdaki durumlarda yararlı olabilir:

  • orijinal işlevi değiştirmek istemez / değiştiremezsiniz.

  • işlevi değiştirebilirsiniz ancak:

    • kullanarak nullbir seçenek değildir (veya eşdeğeri) (DiegoDD görelim yorumunu )
    • ya bir çağrışımcıyla ya da func_num_args()
    • hayatın birkaç LOC tasarrufuna bağlı

Performans hakkında, çok basit bir test , varsayılan parametreleri almak için Reflection API'sini kullanmanın, işlev çağrısını 25 kat daha yavaş hale getirdiğini ve yine de bir mikrosaniyeden daha az sürdüğünü göstermektedir . Bununla yaşayabilir misin bilmelisin.

Tabii ki, bir döngüde kullanmak istiyorsanız, varsayılan değeri önceden almalısınız.


1
Bunu yapmak istememenin sebebi nedir? Oldukça kullanışlı görünüyor.
Bryan

10
function image(array $img)
{
    $defaults = array(
        'src'    => 'cow.png',
        'alt'    => 'milk factory',
        'height' => 100,
        'width'  => 50
    );

    $img = array_merge($defaults, $img);
    /* ... */
}

2
Bir şey mi kaçırıyorum? Bu soruya hiç cevap vermiyor gibi görünüyor, ancak 7 upvotes var. Belki biraz açıklama eklemek yardımcı olabilir?
Sean the Bean

3
@SeantheBean: true, bir açıklama daha iyi olurdu, ancak amacı: PHP'nin isimlendirilmiş argümanları olmadığından, tek parametresi olarak ilişkilendirilebilir bir dizi kullanın.
MestreLion

1
$defaults = [ 'x' => 'some value', 'y' => 'some other value'];
Frank Forte

4

Bunu yapmanın tek yolu parametreyi atlamaktır. Parametresini atlamak için tek yol omit istediğiniz bir o parametreler sonra olacak şekilde parametre listesini yeniden düzenlemek olduğunu VAR sete. Örneğin:

function foo($blah, $y = "some other value", $x = "some value")

Sonra foo gibi arayabilirsiniz:

foo("blah", "test");

Bunun sonucu:

$blah = "blah";
$y = "test";
$x = "some value";

3

Geçenlerde bu sorunu yaşadım ve bu soru ve cevapları buldum. Yukarıdaki sorular işe yararken, sorun, onu destekleyen IDE'lere (PHPStorm gibi) varsayılan değerleri göstermemesidir.

resim açıklamasını buraya girin

kullanırsanız nullboş bırakırsanız değerin ne olacağını bilemezsiniz.

Tercih ettiğim çözüm, varsayılan değeri fonksiyon tanımına da koymaktır:

protected function baseItemQuery(BoolQuery $boolQuery, $limit=1000, $sort = [], $offset = 0, $remove_dead=true)
{
    if ($limit===null) $limit =1000;
    if ($sort===null) $sort = [];
    if ($offset===null) $offset = 0;
    ...

Tek fark, aynı olduklarından emin olmam gerekiyor - ama bu ek netlik için ödemek için küçük bir fiyat olduğunu düşünüyorum.


ReflectionFunction'un dahili kullanımı fiyatı kurtaracaktır!
SubjectDelta

2

Bunu doğrudan yapamazsınız, ancak küçük bir kod uğraşması taklit etmeyi mümkün kılar.

function foo($blah, $x = false, $y = false) {
  if (!$x) $x = "some value";
  if (!$y) $y = "some other value";

  // code
}

6
Bu işe yarardı, ancak nullbu örnekte kavramsal olarak daha gerçekçi olduğunu düşünüyorum false.
TRiG

TriG'nin yorumuna eklemek falsedaha riskli bir seçimdir null, çünkü php katı olmayan bir dildir. !$xprogramcıyı şaşırtabilecek birkaç farklı giriş için doğru olacaktır: 0, ''. Halbuki daha katı bir test olarak nullkullanabilirsiniz !isset.
ToolmakerSteve

1
<?php
function info($name="George",$age=18) {
echo "$name is $age years old.<br>";
}
info();     // prints default values(number of values = 2)
info("Nick");   // changes first default argument from George to Nick
info("Mark",17);    // changes both default arguments' values

?>

1

Boş birleştirici operatörlü 2 sentim?? (PHP 7'den beri)

function foo($blah, $x = null, $y = null) {
    $varX = $x ?? 'Default value X';
    $varY = $y ?? 'Default value Y';
    // ...
}

Benim repl.it daha fazla örnek kontrol edebilirsiniz


0

Bu durum, nesne daha iyi olduğunda - nesnenizi x ve y tutacak şekilde ayarlayabileceğiniz, varsayılanları ayarlayabileceğiniz vb.

Dizi ile yaklaşım, nesne oluşturmak için yakındır (Aslında, nesne, nesne üzerinde çalışacak parametreler ve işlevler grubudur ve işlev alma dizisi, bazı grup parametreleri üzerinde çalışacaktır)

Cerainly, null veya bunun gibi bir şeyi varsayılan olarak ayarlamak için her zaman bazı hileler yapabilirsiniz


0

Bağımsız değişken olarak boş bir dizeniz olup olmadığını da kontrol edebilirsiniz, böylece şöyle çağırabilirsiniz:

foo('blah', "", 'non-default y value', null);

Fonksiyonun altında:

function foo($blah, $x = null, $y = null, $z = null) {
    if (null === $x || "" === $x) {
        $x = "some value";
    }

    if (null === $y || "" === $y) {
        $y = "some other value";
    }

    if (null === $z || "" === $z) {
        $z = "some other value";
    }

    code here!

}

Dolduruyorsa önemli değil nullya ""hala aynı sonucu alırsınız.


0

Tekli parametreler yerine işleve bir dizi iletin ve null birleştirme operatörü (PHP 7+) kullanın.

Aşağıda, 2 öğe içeren bir dizi geçiyorum. İşlev içinde, varsayılan kasa atanmamışsa item1 için değerin ayarlanıp ayarlanmadığını kontrol ediyorum.

$args = ['item2' => 'item2',
        'item3' => 'value3'];

    function function_name ($args) {
        isset($args['item1']) ? $args['item1'] : 'default value';
    }

$args['item1'] = $args['item1']??'default value'; PHP 7 ve üstü sürümlerde kullanabilirsiniz . $ args ['item1'] boşsa, default valuedize $ args ['item1'] 'a
atayacaktır
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.