2

関数の引数としてオプションのリストを渡したいと思います。

理想的なシナリオ: 名前付きパラメーター

PHP に名前付きパラメーターがある場合は、次のようになります。

function setOptions($title, $url, $public = true, $placeholder = "type here...") {
   ...
}

setOptions($title = "Hello World", $url = "example.com", $placeholder = "hi"); 

残念ながら、PHP には名前付きパラメーターがありませ(PHP7 でコメントとしてパラメーターを指定する予定があるかどうか教えてください)

他の誰もが使用しているソリューション: 連想配列

私が見たほとんどの PHP スクリプトは、次のような代替配列アプローチを使用しています。

function setOptions($options) {
   ...
}

setOptions(array(
   'title' => "Hello World",
   'url' => "example.com",
   'placeholder' => "hi"
));

連想配列アプローチの欠点

これは問題なく動作しますが、次の欠点があります。

  • ユーザーはオートコンプリートの恩恵を受けません (書き込みに時間がかかります)
  • ユーザーはスペルを間違えやすい
  • 利用可能なオプションがわからないため、頻繁にドキュメントに戻る可能性があります

より良い方法はありますか?

これらの問題に対処できるより良い方法はありますか (現在の PHP または PHP7、あるいは hacklang(?) のいずれか)。

4

5 に答える 5

3

Hack では、 Shapesを使用できます。形状は連想配列の構造を定義するため、(IDE のサポートに応じて) オートコンプリートが可能になり、タイプ チェッカーによってスペル ミスが検出されます。

たとえば、あなたの例は次のように作り直すことができます:

function setOptions(shape(
  'title' => string,
  'url' => string,
  'public' => ?bool,
  'placeholder' => ?string,
) $options) {
  $title = $options['title'];
  $url = $options['url'];
  $public = Shapes::idx($options, 'public', true);
  $placeholder = Shapes::idx($options, 'placeholder', 'type here...');
  ...
}

setOptions(shape(
  'title' => 'Hello World',
  'url' => 'example.com',
  'placeholder' => 'hi',
));

このマークtitleおよびurlは両方とも必須オプションであり、publicおよびplaceholderはオプションです (シェイプ内のすべての null 許容型はオプションと見なされます)。Shapes::idx次に、提供された値、または値が渡されなかった場合のデフォルト値 (3 番目の引数) を取得するために使用されます。

于 2015-09-06T05:14:05.780 に答える
2

解決策: 流暢なセッターを使用する

この問題に対して私が見つけた潜在的な解決策は、次のようにクラスと流暢なセッターを使用することです。

class PostOptions {

    protected
      $title,
      $url,
      $public = TRUE,
      $placeholder = "type here..."; //Default Values can be set here

    static function getInstance(): PostOptions {
        return new self();
    }

    public function setTitle($title) {
        $this->title = $title;
        return $this;
    }

    public function setUrl($url) {
        $this->url = $url;
        return $this;
    }

    public function setPublic($public) {
        $this->public = $public;
        return $this;
    }

    public function setPlaceholder($placeholder) {
        $this->placeholder = $placeholder;
        return $this;
    }

}

その後、次のようにオプションを送信できます。

function setOptions(PostOptions $postOptions) {
    //...
}

setOptions(
  PostOptions::getInstance()
             ->setTitle("Hello World")
             ->setUrl("example.com")
             ->setPlaceholder("hi")
);

手っ取り早く!(これは長く見えます)

これは長く見えるかもしれませんが、実際にはIDE ツールを使用して非常に迅速に実装できます。

たとえば、InteliJ または PHPStorm では、次のように入力してALT+INS> 選択setters> 設定するフィールドを選択し、チェックボックスをオンにしてfluent setters> をクリックします。OK

流暢なセッターを選ぶ理由 すべてのフィールドを公開しないのはなぜですか?

public フィールドを使用すると、かなり遅くなります。これは、流暢なセッターがチェーンされたメソッドを利用できるためですが、パブリック フィールドの方法は次のように記述する必要があります。

$options = new PostOptions(); 
$options->title = "hello"; 
$options->placeholder = "..."; 
$options->url "..."
setOptions($options); 

提案されたソリューションと比較して、これはより多くのタイピングです

なぜこれが良いのですか?

  • 配列アプローチよりもオートコンプリートを使用すると、IDE の方が高速です。
  • スペルを間違えにくい (オートコンプリートのおかげ)
  • 利用可能なオプションを簡単に確認できます (これもオートコンプリートのおかげです)
  • PHPDoc を使用して、個々のフィールドに個別のドキュメントを提供できます
  • ネストされたオプションをより簡単に使用できます。たとえば、オプションのリストがあり、そのオプションにもさらにオプションのリストがある場合
  • その他の OOP の利点 (継承と抽象クラスなど)

このアプローチはどれくらい高速ですか?

WordPress ラベル配列のクイック クラスを実装しました: https://codex.wordpress.org/Function_Reference/register_post_type

オートコンプリートのおかげで、流暢なセッター アプローチが配列アプローチよりも約25%高速であることがわかりました (2 番目のモニターの横にあるドキュメントを使用して) 各値のプロパティを設定します。ただし、ドキュメンテーションがあなたの隣になかった場合、オプションの発見がはるかに速いため、このアプローチは25% をはるかに超えると思います!

代替アプローチを歓迎します

于 2015-09-05T23:23:51.993 に答える
1

配列からの宣言

これは、通常、クラス構造を宣言する方法です。唯一の欠点は、書き込みに時間がかかることですが、オプションのパラメーター、デフォルト値などを使用できます。

public static $defaults = array(
    'user_id' => null,
    'username' => null,
    'avatar' => null,
    'email' => null,
    'description' => null,
);

public function __construct(array $args = array()) {
    $this->dbc = Database::connection();
    $defaults = self::$defaults;
    $args = array_merge($defaults, $args);

    //Assign the object properites
    $this->user_id = (is_numeric($args['user_id'])) ? $args['user_id'] : null;
    $this->username = $args['username'];
    $this->avatar = AVATAR_DIR . $args['avatar'];
    $this->email = $args['email'];
    $this->description = $args['description'];
}

このようにして、 のようなオブジェクトを宣言することができ$x = new User()、それは完全に正常に動作します。SQLステートメントからいくつかの列のみを選択したとします。を選択したものと同じ名前にするkeysことができます。その方法でオブジェクトをインスタンス化すると、簡単に実行できます。public static $defaultscolumns

$row = mysqli_fetch_array($result, MYSQLI_ASSOC);
$object = new User($row);

array_merge、提供された引数で必要のない不要なキーを処理します。オプションを変更する必要がある場合は__construct()、デフォルト配列を使用して同じ方法で宣言し、array_merge引数をキャッチして、名前付きパラメーターとデフォルト値を模倣することができます (Python のように)。

于 2015-09-06T00:15:45.487 に答える
0

With Syntactic: https://github.com/topclaudy/php-syntactic

you can just do:

function foo($a = 1, $b = 2, $c = 3, $d = 4){
    return $a * $b * $c * $d;
}

And call it with the arguments you want:

//Call with argument b only
echo s('foo')->in('b', 5)->out(); //Outputs 60

//Call with argument a and argument at index/position 1 (b),
echo s('foo')->in('a', 7)->in(1, 5)->out(); //Outputs 420

//Call with argument c only through dynamic method
echo s('foo')->c(9)->out(); //Outputs 72
于 2016-06-20T17:00:07.187 に答える
0

U にそれほど多くのパラメーターがある場合は、n 個のパラメーターの代わりにクラスに渡すオブジェクトを作成することを検討します。すべてのパラメーターは 1 つのフィールドです。コンストラクターに必要なパラメーターを入力すると、これがクリーンなソリューションになります。

于 2018-05-17T13:27:33.120 に答える