Bir işlev çağrısında isteğe bağlı argümanları nasıl atlarım?


96

Tamam PHP'de argümanların nasıl atlanacağını tamamen unuttum.

Diyelim ki bende var:

function getData($name, $limit = '50', $page = '1') {
    ...
}

Ortadaki parametrenin varsayılan değeri alması için bu işlevi nasıl çağırırım (ör. '50')?

getData('some name', '', '23');

Yukarıdakiler doğru olur mu? Bunu çalıştıracak gibi görünmüyorum.


1
@Chuck tam olarak ne arıyorsun? Bir geçici çözüm veya bunu uygulamak için bir sınıf gibi mi yoksa ...?
Rizier123

@ Rizier123 PHP'nin mevcut sürümünün argüman atlamayı destekleyip desteklemediğini soruyorum (diğer dillerde olduğu gibi). Mevcut cevaplar güncel olmayabilir. Ödül açıklamasından: "Mevcut cevaplar beş yıllıktır. PHP'nin mevcut sürümü bir şeyleri değiştiriyor mu?"
Chuck Le Butt

1
@Chuck O zaman cevap muhtemelen: hiçbir şey değişmedi; bir geçici çözüm / kod olmadan işlevselliğinizi alamazsınız.
Rizier123

Buradaki tüm cevaplar, çağrılan işlev üzerinde kontrole sahip olduğunuzu varsayıyor. Bu işlev bir kitaplığın veya çerçevenin parçasıysa, bağımsız değişken 3'e ihtiyacınız varsa, bağımsız değişken 2 için bir şey belirtmekten başka seçeneğiniz yoktur. Tek seçenek, işlev için kaynağa bakmak ve varsayılan değeri çoğaltmaktır.
Snapey

Bunu atlamak mümkün değildir, ancak varsayılan argümanı kullanarak geçebilirsiniz ReflectionFunction. Bu yanıtı benzer bir soruda yayınladım .
David

Yanıtlar:


56

Gönderiniz doğru.

Ne yazık ki, parametre listesinin en sonunda isteğe bağlı bir parametre kullanmanız gerekirse, o son parametreye kadar her şeyi belirtmeniz gerekir. Genellikle karıştırıp eşleştirmek istiyorsanız, onlara ''veya varsayılan değerlerini verirsiniz nullve bu varsayılan değer iseler bunları işlev içinde kullanmayın.


1
Bir örnek verebilir misiniz?
i am me

2
@iamme yapmak $limit = is_numeric($limit) ? $limit : '50';başında getData fonksiyonu
Kamafeather

41

falseVeya gibi varsayılan bir argümanı belirtmekten başka bir argümanı "atlamanın" bir yolu yoktur null.

Konu bu olunca PHP biraz sözdizimsel şekere sahip olmadığından, genellikle şöyle bir şey göreceksiniz:

checkbox_field(array(
    'name' => 'some name',
    ....
));

Bu, açıklamalarda açıkça belirtildiği gibi, adlandırılmış argümanları taklit etmek için dizileri kullanmaktır.

Bu, nihai esneklik sağlar ancak bazı durumlarda gerekli olmayabilir. En azından, beklenmediğini düşündüğünüz her şeyi çoğu zaman argüman listesinin sonuna taşıyabilirsiniz.


2
'Bunun gibi bir şeyi', 'adlandırılmış bağımsız değişkenleri taklit etmek için dizileri kullanmak' olarak tanımlardım, FWIW. :)
kaos

3
Daha esnek olmasına rağmen, ayarlamanız / yapabileceğiniz parametreleri hatırlamanız gerekir (imzada olmadığı için). Yani sonuçta göründüğü kadar faydalı olmayabilir ama elbette bu bağlama bağlı.
Felix Kling

Öyleyse, böyle bir senaryo için en iyi uygulamalar nelerdir?
Adam Grant

39

Hayır, argümanları bu şekilde atlamak mümkün değil. Yalnızca parametre listesinin sonundaysa bağımsız değişkenleri iletmeyi atlayabilirsiniz .

Bunun için resmi bir öneri vardı: https://wiki.php.net/rfc/skipparams , reddedildi. Teklif sayfası, bu konuyla ilgili diğer SO sorularına bağlantı verir.


Öyleyse PHP işlevlerinin daha fazla / daha az parametresi isteğe bağlı olarak nasıl olur?
i am me

2
PHP, varsayılan parametre değerlerini destekler. Ancak bu parametreler listenin sonunda yer almalıdır.
Cristik

1
Örnekleri PHP belgelerinde
Cristik

2
Gerizekalılar. Beni çok kızdırıyor. Başkasının istediği bir özelliği beğenmezseniz, kullanmayın. İnternet bazen en kötüsüdür.
Lee Saxon

@LeeSaxon konu okunabilirlik ve taşınabilirliktir. 1) Birisi parametreleri atlamaya karar verirse ve kodda hata ayıklayan biri bu gerçeği kaçırırsa, büyük bir kafa karışıklığı oluşur. 2) yeni kod, büyük bir aşırı yük olmadan eski sürümlerde çalışamaz ve hata olasılığı çok yüksektir.
Mark Walsh

6

İsteğe bağlı bağımsız değişkenleri atlayabilme konusunda hiçbir şey değişmedi, ancak doğru sözdizimi için ve atlamak istediğim bağımsız değişkenler için NULL belirleyebilmek için bunu şu şekilde yapacağım:

define('DEFAULT_DATA_LIMIT', '50');
define('DEFAULT_DATA_PAGE', '1');

/**
 * getData
 * get a page of data 
 *
 * Parameters:
 *     name - (required) the name of data to obtain
 *     limit - (optional) send NULL to get the default limit: 50
 *     page - (optional) send NULL to get the default page: 1
 * Returns:
 *     a page of data as an array
 */

function getData($name, $limit = NULL, $page = NULL) {
    $limit = ($limit===NULL) ? DEFAULT_DATA_LIMIT : $limit;
    $page = ($page===NULL) ? DEFAULT_DATA_PAGE : $page;
    ...
}

Bu şu şekilde çağrılabilir: getData('some name',NULL,'23');ve gelecekte işlevi çağıran herhangi birinin her seferinde varsayılanları veya onlar için bildirilen sabiti hatırlamasına gerek yoktur.


1
Muhtemelen kesin bir karşılaştırma istersiniz ($ limit === boş)
roelleor

4

Basit cevap Hayır . Ama argümanları yeniden düzenlerken bunu neden atlayın?

Sizinki, " Varsayılan işlev bağımsız değişkenlerinin yanlış kullanımı " ve beklediğiniz gibi çalışmayacaktır.

PHP belgelerinden bir yan not:

Varsayılan argümanlar kullanılırken, varsayılanlar, varsayılan olmayan argümanların sağ tarafında olmalıdır; aksi takdirde işler beklendiği gibi çalışmayacaktır.

Aşağıdakileri göz önünde bulundur:

function getData($name, $limit = '50', $page = '1') {
    return "Select * FROM books WHERE name = $name AND page = $page limit $limit";
}

echo getData('some name', '', '23');   // won't work as expected

Çıktı şu şekilde olacaktır:

"Select * FROM books WHERE name = some name AND page = 23 limit"

Varsayılan işlev argümanlarının doğru kullanımı şu şekilde olmalıdır:

function getData($name, $page = '1', $limit = '50') {
    return "Select * FROM books WHERE name = $name AND page = $page limit $limit";
}

echo getData('some name', '23');  // works as expected

Çıktı şu şekilde olacaktır:

"Select * FROM books WHERE name = some name AND page = 23 limit 50"

Varsayılanı, varsayılan olmayanlardan sonra sağınıza koymak, tanımlanmamış / verilmemişse, o değişken için varsayılan değeri her zaman yeniden çalıştıracağından emin olmanızı sağlar. İşte referans için bir bağlantı ve bu örneklerin nereden geldiği.

Düzenleme: nullBaşkalarının önerdiği şekilde ayarlamak işe yarayabilir ve başka bir alternatiftir, ancak istediğinizi uygun olmayabilir. Tanımlanmamışsa, her zaman varsayılanı null olarak ayarlar.


Açıkça resmedilmiş sözdizimsel açıklamalar sağladığı için bu en iyi cevaptır! Teşekkür ederim!
Christian

2

Atlanan herhangi bir parametre için (yapmanız gerekir), güvenli tarafta olmak için varsayılan parametreye gidin.

(Varsayılan parametrenin '' veya benzeri olduğu ya da tam tersinin olduğu yerlerde boş değeri ayarlamak sizi sorunlara sürükleyecektir ...)


2

Yukarıda bahsedildiği gibi, parametreleri atlayamazsınız. Bu yanıtı, bir yoruma yerleştirilemeyecek kadar büyük bir ek sağlamak için yazdım.

@Frank Nocke , işlevi varsayılan parametreleriyle çağırmayı önerir , bu nedenle örneğin

function a($b=0, $c=NULL, $d=''){ //...

kullanmalısın

$var = a(0, NULL, 'ddd'); 

işlevsel olarak ilk iki ( $bve $c) parametrenin çıkarılmasıyla aynı olacaktır .

Hangilerinin varsayılan olduğu açık değildir ( 0varsayılan değeri sağlamak için mi yazılmıştır yoksa önemli mi?).

Varsayılan değerler işlev (veya yöntem) yazarı tarafından değiştirilebildiğinde, varsayılan değerler sorununun harici (veya yerleşik) işleve bağlı olma tehlikesi de vardır. Yani programdaki çağrınızı değiştirmezseniz, istemeden davranışını değiştirebilirsiniz.

Bazı geçici çözümler, DEFAULT_A_B"A işlevinin B parametresinin varsayılan değeri" ve parametreleri bu şekilde "atla" gibi bazı genel sabitleri tanımlamak olabilir :

$var = a(DEFAULT_A_B, DEFAULT_A_C, 'ddd');

Sınıflar için, sınıf sabitlerini tanımlarsanız daha kolay ve daha zariftir, çünkü bunlar genel kapsamın bir parçasıdır, örn.

class MyObjectClass {
  const DEFAULT_A_B = 0;

  function a($b = self::DEFAULT_A_B){
    // method body
  }
} 
$obj = new MyObjectClass();
$var = $obj->a(MyObjectClass::DEFAULT_A_B); //etc.

Bu varsayılan sabitin kod boyunca tam olarak bir kez tanımlandığını unutmayın (yöntem bildiriminde bile değer yoktur), bu nedenle bazı beklenmedik değişiklikler olması durumunda, her zaman işlevi / yöntemi doğru varsayılan değerle sağlayacaksınız.

Bu çözümün netliği elbette okuyucuya hiçbir şey söylemeyen ham varsayılan değerler (gibi NULL, 0vb.)

(Beğenmenin $var = a(,,'ddd');en iyi seçenek olduğuna katılıyorum )


2

Bağımsız değişkenleri atlayamazsınız, ancak dizi parametrelerini kullanabilirsiniz ve yalnızca bir parametre dizisi olan 1 parametre tanımlamanız gerekir.

function myfunction($array_param)
{
    echo $array_param['name'];
    echo $array_param['age'];
    .............
}

İhtiyaç duyduğunuz kadar parametre ekleyebilirsiniz, bunları tanımlamanıza gerek yoktur. Fonksiyonu çağırdığınızda, parametrelerinizi şu şekilde koyarsınız:

myfunction(array("name" => "Bob","age" => "18", .........));

1

Bu, teknik olarak yetkin cevaplar içeren eski bir sorudur, ancak PHP'deki modern tasarım modellerinden biri olan Nesne Yönelimli Programlama'yı haykırmaktadır. İlkel skaler veri türleri koleksiyonunu enjekte etmek yerine, işlevin ihtiyaç duyduğu tüm verileri içeren bir "enjekte edilmiş nesne" kullanmayı düşünün. http://php.net/manual/en/language.types.intro.php

Enjekte edilen nesnenin özellik doğrulama rutinleri olabilir. Enjekte edilen nesneye verilerin somutlaştırılması ve enjeksiyonu tüm doğrulamayı geçemezse, kod hemen bir istisna atabilir ve uygulama garip işlemlerden kaçınabilir. potansiyel olarak eksik verilerle.

Dağıtımdan önce hataları yakalamak için enjekte edilen nesneyi yazarak ipucu verebiliriz. Bu makalede birkaç yıl önceki fikirlerden bazıları özetlenmiştir.

https://www.experts-exchange.com/articles/18409/Using-Named-Parameters-in-PHP-Function-Calls.html


0

Herkesin söylediği gibi, istediğiniz şeyin PHP'de işleve herhangi bir kod satırı eklemeden mümkün olmayacağını söyledi.

Ancak, işlevselliğinizi elde etmek için bu kod parçasını bir işlevin en üstüne yerleştirebilirsiniz:

foreach((new ReflectionFunction(debug_backtrace()[0]["function"]))->getParameters() as $param) {
    if(empty(${$param->getName()}) && $param->isOptional())
        ${$param->getName()} = $param->getDefaultValue();
}

Yani temelde, debug_backtrace()yeni bir ReflectionFunctionnesne oluşturmak ve tüm fonksiyon argümanlarında döngü yapmak için bu kodun yerleştirildiği fonksiyon adını alırım .

Döngüde, fonksiyon argümanının empty()AND olup olmadığını kontrol ederim ve argüman "isteğe bağlı" (varsayılan bir değeri olduğu anlamına gelir). Eğer evet ise, varsayılan değeri argümana atarım.

Demo


0

Sınırı boş olarak ayarlayın

function getData($name, $limit = null, $page = '1') {
    ...
}

ve o işlevi çağırın

getData('some name', null, '23');

sınırı ayarlamak istiyorsanız, argüman olarak geçebilirsiniz

getData('some name', 50, '23');

0

Daha önce tavsiye edildiği gibi gibi hiçbir şey değişmedi. Ancak, çok fazla parametre (özellikle isteğe bağlı olanlar), kod kokusunun güçlü bir göstergesidir.

Belki de işleviniz çok fazla şey yapıyor:

// first build context
$dataFetcher->setPage(1);
// $dataFetcher->setPageSize(50); // not used here
// then do the job
$dataFetcher->getData('some name');

Bazı parametreler mantıksal olarak gruplandırılabilir:

$pagination = new Pagination(1 /*, 50*/);
getData('some name', $pagination);
// Java coders will probably be familiar with this form:
getData('some name', new Pagination(1));

Son çare olarak, her zaman geçici bir parametre nesnesi tanıtabilirsiniz :

$param = new GetDataParameter();
$param->setPage(1);
// $param->setPageSize(50); // not used here
getData($param);

(ki bu daha az resmi olanın yüceltilmiş bir versiyonudur. parametre dizisi tekniğinin)

Bazen, bir parametreyi isteğe bağlı yapmanın nedeni yanlıştır. Bu örnekte, $pagegerçekten isteğe bağlı olması mı gerekiyor? Birkaç karakteri kaydetmek gerçekten bir fark yaratır mı?

// dubious
// it is not obvious at first sight that a parameterless call to "getData()"
// returns only one page of data
function getData($page = 1);

// this makes more sense
function log($message, $timestamp = null /* current time by default */);

0

Bu pasaj:

    function getData ($ ad, $ seçenekler) {
       $ varsayılan = dizi (
            'limit' => 50,
            'sayfa' => 2,
        );
        $ değiştirgeler = array_merge ($ varsayılan, $ seçenekler);
        print_r ($ değiştirgeler);
    }

    getData ('foo', dizi ());
    getData ('foo', dizi ('sınır' => 2));
    getData ('foo', array ('limit' => 10, 'sayfa' => 10));

Cevap:

     Dizi
    (
        [limit] => 50
        [sayfa] => 2
    )
    Dizi
    (
        [limit] => 2
        [sayfa] => 2
    )
    Dizi
    (
        [limit] => 10
        [sayfa] => 10
    )


2
Güzel. Ancak küçük bir açıklama yardımcı olacaktır.
showdev

Güzel yanıt, ancak isteğe bağlı parametreyi atlamak istiyorsanız, bunu şu şekilde yapın: function getData ($ name, $ args = array ()) {$ default = array ('limit': => 50, 'page' => 2) ; $ değiştirgeler = array_merge ($ varsayılanlar, $ değiştirgeler); } Artık bu işlevi yalnızca aşağıdaki gibi ilk parametre ile çağırmak mümkündür: getData ('foo');
EchoSin

0

Yapacağım şey bu:

<?php

    function getData($name, $limit = '', $page = '1') {
            $limit = (EMPTY($limit)) ? 50 : $limit;
            $output = "name=$name&limit=$limit&page=$page";
            return $output;
    }

     echo getData('table');

    /* output name=table&limit=50&page=1 */

     echo getData('table',20);

    /* name=table&limit=20&page=1 */

    echo getData('table','',5);

    /* output name=table&limit=50&page=5 */

    function getData2($name, $limit = NULL, $page = '1') {
            $limit = (ISSET($limit)) ? $limit : 50;
            $output = "name=$name&limit=$limit&page=$page";
            return $output;
    }

    echo getData2('table');

    // /* output name=table&limit=50&page=1 */

    echo getData2('table',20);

    /* output name=table&limit=20&page=1 */

    echo getData2('table',NULL,3);

    /* output name=table&limit=50&page=3 */

?>

Umarım bu birine yardımcı olur


0

İsteğe bağlı parametrelerle bir Fabrika yapmak zorunda kaldım, çözümüm boş birleştirme operatörünü kullanmaktı:

public static function make(
    string $first_name = null,
    string $last_name = null,
    string $email = null,
    string $subject = null,
    string $message = null
) {
    $first_name = $first_name ?? 'First';
    $last_name  = $last_name ?? 'Last';
    $email      = $email ?? 'foo@bar.com';
    $subject    = $subject ?? 'Some subject';
    $message    = $message ?? 'Some message';
}

Kullanım:

$factory1 = Factory::make('First Name Override');
$factory2 = Factory::make(null, 'Last Name Override');
$factory3 = Factory::make(null, null, null, null 'Message Override');

En güzel şey değil, ancak fabrikalarda testler için kullanmak için iyi bir model olabilir.


-1

Bunu dene.

function getData($name, $limit = NULL, $page = '1') {
               if (!$limit){
                 $limit = 50;
               }
}

getData('some name', '', '23');

-1

İşlev çağrınızda orta parametreyi atlayamazsınız. Ancak, bununla çalışabilirsiniz:

function_call('1', '2', '3'); // Pass with parameter.
function_call('1', null, '3'); // Pass without parameter.

İşlev:

function function_call($a, $b='50', $c){
    if(isset($b)){
        echo $b;
    }
    else{
        echo '50';
    }
}

Neden eksi oylarınız olduğundan emin değilim, $ c dışında ayrıca bir varsayılan değere ihtiyaç duyuyorsunuz (isteğe bağlı bir argümandan sonra gerekli herhangi bir argümanınız olamaz).
Frank Forte

-2

@ İbrahimLawal'ın belirttiği gibi. Onları sadece nulldeğerlere ayarlamak en iyi uygulamadır . Yalnızca null, tanımlanan varsayılanları kullandığınız, geçirilen değerin olup olmadığını kontrol edin .

<?php
define('DEFAULT_LIMIT', 50);
define('DEFAULT_PAGE', 1);

function getData($name, $limit = null, $page = null) {
    $limit = is_null($limit) ? DEFAULT_LIMIT : $limit;
    $page = is_null($page) ? DEFAULT_PAGE : $page;
    ...
}
?>

Bu yardımcı olur umarım.


Yanıtı kopyaladınız. Aksine, oy verebilir veya yorum yapabilirdiniz.
Ibrahim Lawal

-6
getData('some name');

sadece onları geçmeyin ve varsayılan değer kabul edilecektir

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.