如何使函数参数在数组和字符串中都可选,使用同一个变量。

huangapple go评论55阅读模式
英文:

How to make a function parameter optional for both an array and a string using the same variable

问题

我想要一个变量,可以作为数组或字符串传递给我的函数,并使它们可选。这是示例函数:

function myFunction(string $msg = '' || array $msg = []) { // 这是第9行
    if(is_string($msg)) {
        echo "我是字符串";
    } else if (is_array($msg)){
        echo "我是数组";
    }
}

这种可能吗?我找不到具体显示这一点的东西。当我尝试在测试页面上运行此函数时,我收到以下错误:

> 解析错误:语法错误,意外的变量 "$msg",期望 "("

> 在 /Path/To/My/File/test.php 的第9行

我查看了 PHP 函数参数的官方文档:https://www.php.net/manual/en/functions.arguments.php,并且其中写道:

> 信息可以通过参数列表传递给函数,该列表是逗号分隔的表达式列表。在实际调用函数之前(急切评估)从左到右评估参数。

那么我写的为什么不起作用呢?

编辑... 这是我实际使用的方法。

public function flash(string|array $name = '', string|array $message = '', string $type = '') {
    if (!empty($name) && !empty($message) && $type !== '') {
        // 创建一个闪存消息
        $this->createFlashMessage($name, $message, $type);
    } elseif ($name !== '' && $message === '' && $type === '') {
        // 显示一个闪存消息
        return $this->displayFlashMessage($name);
    } elseif ($name === '' && $message === '' && $type === '') {
        // 显示所有闪存消息
        return $this->displayAllFlashMessages();
    }
}

第一个参数接受一个名称,比如 error_msg,并将其分配给

> $_SESSION[FLASH_MESSAGE][$name]

$name 是 'error_msg'。对于单个实例,它可以正常工作。但是,当在同一个文件输入字段上发生多次上传时,我遇到了一种情况,如果有多个上传出现多个错误:

<input type="file" name="upload[]" multiple>

当我调用 $load = $upload->uploadFile 方法时,它可能会返回一个准备输入到数据库的文件名的逗号分隔列表的字符串。字符串是逗号分隔列表,或者 uploadFile 将返回一个包含错误的数组:

> $upload = ['server_error' => ['message' => '错误消息在这里', 'type' => 'FLASH_ERROR']];

但是,在同一上传中出现多个错误的情况下,然后:

> $upload = ['server_error' => [['message' => '第一个错误消息', 'type' => 'FLASH_ERROR'],['message' => '第二个错误消息', 'type' => 'FLASH_MESSAGE']]];

这就是为什么我需要能够传递数组、字符串或什么都不传递的原因... 附带一提,我的括号可能在这里可能不正确 如何使函数参数在数组和字符串中都可选,使用同一个变量。 我仍在尝试切换到使用括号而不是使用 array(array()):D

英文:

I want to have a variable that is passed to my function as either an array or a string and have them optional. Here is the sample function:

function myFunction(string $msg = &#39;&#39; || array $msg = []) { // This is line 9
	if(is_string($msg)) {
		echo &quot;I&#39;m a string&quot;;
	} else if (is_array($msg)){
		echo &quot;I&#39;m an array&quot;;
	}
}

Is this possible? I can't find anything that specifically shows this. When I try to run this function on a test page I get the following error:

> Parse error: syntax error, unexpected variable "$msg", expecting "("
> in /Path/To/My/File/test.php on line
> 9

I have looked at the php manual for function arguments: https://www.php.net/manual/en/functions.arguments.php and it states:

> Information may be passed to functions via the argument list, which is
> a comma-delimited list of expressions. The arguments are evaluated
> from left to right, before the function is actually called (eager
> evaluation).

So why wouldn't what I wrote work?

EDIT... Here is the actual method that I'm using.

public function flash(string|array $name = &#39;&#39;, string|array $message = &#39;&#39;, string $type = &#39;&#39;) {
	if (!empty($name) &amp;&amp; !empty($message) &amp;&amp; $type !== &#39;&#39;) {
		// create a flash message
		$this-&gt;createFlashMessage($name, $message, $type);
	} elseif ($name !== &#39;&#39; &amp;&amp; $message === &#39;&#39; &amp;&amp; $type === &#39;&#39;) {
		// display a flash message
		return $this-&gt;displayFlashMessage($name);
	} elseif ($name === &#39;&#39; &amp;&amp; $message === &#39;&#39; &amp;&amp; $type === &#39;&#39;) {
		// display all flash message
		return $this-&gt;displayAllFlashMessages();
	}
}

The first paramter takes a name, like error_msg and it will assign it to a

> $_SESSION[FLASH_MESSAGE][$name]

$name being the 'error_msg'. It works fine for single instances. But I have run across a situation while uploading image files if there are multiple errors with multiple uploads on the same file input field,

&lt;input type=&quot;file&quot; name=&quot;upload[]&quot; multiple&gt;

When I call the $load = $upload->uploadFile method it can either return a string with the file names ready to input into the database. The string is a comma deliminated list or uploadFile will return an array with the errors:

> $upload = ['server_error => ['message' => 'Error message here', 'type' => 'FLASH_ERROR']];

But in the instance where there are multiple errors on the same upload, then:

> $upload = ['server_error' => [['message' => 'First error message', 'type' => 'FLASH_ERROR'],['message' => 'Second Error message', 'type' => 'FLASH_MESSAGE']]];

But that is why I was needing to be able to pass either an array, string or nothing... on a side note, my brackets may or may not be properly on here 如何使函数参数在数组和字符串中都可选,使用同一个变量。 I'm still trying to switch over to using the brackets rather than using array(array()) 如何使函数参数在数组和字符串中都可选,使用同一个变量。

答案1

得分: 3

It is posible, but the default value must be one of the types in your union type (Available since PHP 8.0):

function myFunction(string|array $msg = [])

//OR

function myFunction(string|array $msg = '')
英文:

It is posible, but the default value must be one of the types in your union type (Available since PHP 8.0):

function myFunction(string|array $msg = [])

//OR

function myFunction(string|array $msg = &#39;&#39;)

答案2

得分: 2

  1. 复合类型: https://www.php.net/manual/en/language.types.declarations.php#language.types.declarations.composite
  2. 可空类型: https://www.php.net/manual/en/language.types.declarations.php#language.types.declarations.nullable
function myFunction(string|array $msg = NULL) {
    if( is_null($msg) ) {
        // 进行默认操作?
    }
    var_dump($msg);
}

myfunction();
myfunction('foo');
myfunction(['foo']);

输出:

NULL
string(3) "foo"
array(1) {
  [0]=>
  string(3) "foo"
}

注意:复合类型仅在PHP >= 8中可用。要在PHP < 8中实现此功能,您需要完全省略类型声明,并自行实现检查。例如:

function myFunction($msg = NULL) {
    if( ! in_array(gettype($msg), ['string', 'array', 'NULL']) ) {
        throw new \Exception('Parameter msg not of an acceptable type.');
    }
    var_dump($msg);
}

不过,如果您尝试以更简化的方式适应“一个或多个”,我建议使用以下方式:

function handleOne(string $msg) {
    echo $msg . PHP_EOL;
}

function handleMany(array $msgs) {
    foreach( $msgs as $msg ) {
        handleOne($msg);
    }
}

handleOne('first');
handleMany(['second', 'third']);

这种方法的附加好处是确保所有数组成员都是字符串,而且更容易维护。

英文:
  1. Composite Types: https://www.php.net/manual/en/language.types.declarations.php#language.types.declarations.composite
  2. Nullable Types: https://www.php.net/manual/en/language.types.declarations.php#language.types.declarations.nullable
function myFunction(string|array $msg = NULL) {
    if( is_null($msg) ) {
        // do a default thing?
    }
    var_dump($msg);
}

myfunction();
myfunction(&#39;foo&#39;);
myfunction([&#39;foo&#39;]);

Output:

NULL
string(3) &quot;foo&quot;
array(1) {
  [0]=&gt;
  string(3) &quot;foo&quot;
}

Note: Composite Types are only available in PHP>=8. To accomplish this in PHP<8 you would have to omit the type declaration completely, and implement the check yourself. Eg:

function myFunction($msg = NULL) {
    if( ! in_array(gettype($msg), [&#39;string&#39;, &#39;array&#39;, &#39;NULL&#39;]) ) {
        throw new \Exception(&#39;Parameter msg not of an acceptable type.&#39;);
    }
    var_dump($msg);
}

Though if you're trying to accommodate "one or more" in a simplified manner I would suggest something like the following instead:

function handleOne(string $msg) {
    echo $msg . PHP_EOL;
}

function handleMany(array $msgs) {
    foreach( $msgs as $msg ) {
        handleOne($msg);
    }
}

handleOne(&#39;first&#39;);
handleMany([&#39;second&#39;, &#39;third&#39;]);

Which has the additional benefit of ensuring that all the array members are strings, along with being much easier to maintain.

答案3

得分: 1

A completion to the previous answers can be the casting to an array of the parameter so you can handle it in a single way:

function myFunction(string|array $msg = []) 
{
   foreach ((array)$msg as $m) {
     // manage $msg(s)
   }
}
英文:

A completion to the previous answers can be the casting to array of the parameter so you can handle it in a single way:

function myFunction(string|array $msg = []) 
{
   foreach ((array)$msg as $m) {
     // manage $msg(s)
   }
}

答案4

得分: 1

I am noticing multiple design choices that are leading to headaches and future headaches.

  1. I am hoping that flash() doesn't make circular calls create a flash message. There is a code smells that flash() conditionally returns. It seems that this method is not obeying the "single-responsibility" principle in SOLID design.

  2. While as other have said already, you can use union types in your method signature, the looseness of the input data results in your method(s) needing to awkwardly accommodate it.

  3. !empty($message) is an unreasonable check. $message is never passed into the method, so it will always evaluate as false -- therefore $this->createFlashMessage($name, $message, $type); will never possibly be executed.


In my applications, if an incoming value is expected to be an array (or iterable), I do not allow the parameter to be a non-array type (or non-iterable). Either the array is empty or it is not, but either way, the data can be directly/unconditionally passed into a loop/iterator. In EXTREMELY rare/desperate situations, I may permit a nullable array type with ?array but this is not preferred.

It seems to me that flash() is a flash router/handler, perhaps that should be semantically conveyed in the method name: flashRouter().

I cannot offer complete advice on your script, but from what I gather, displayAllFlashMessages() is built to accept no arguments and will happily process any number of flash messages. I would ditch this flash() method and send all requests to displayAllFlashMessages() and ensure that all calls of that function deliver the data as an array. If those $name and type variables are relevant, pass them to displayAllFlashMessages().

英文:

I am noticing multiple design choices that are leading to headaches and future headaches.

  1. I am hoping that flash() doesn't make circular calls create a flash message. There is a code smells that flash() conditionally returns. It seems that this method is not obeying the "single-responsibility" principle in SOLID design.

  2. While as other have said already, you can use union types in your method signature, the looseness of the input data results in your method(s) needing to awkwardly accommodate it.

  3. !empty($message) is an unreasonable check. $message is never passed into the method, so it will always evaluate as false -- therefore $this-&gt;createFlashMessage($name, $message, $type); will never possibly be executed.


In my applications, if an incoming value is expected to be an array (or iterable), I do not allow the parameter to be a non-array type (or non-iterable). Either the array is empty or it is not, but either way, the data can be directly/unconditionally passed into a loop/iterator. In EXTREMELY rare/desperate situations, I may permit a nullable array type with ?array but this is not preferred.

It seems to me that flash() is a flash router/handler, perhaps that should be semantically conveyed in the method name: flashRouter().

I cannot offer complete advice on your script, but from what I gather, displayAllFlashMessages() is built to accept no arguments and will happily process any number of flash messages. I would ditch this flash() method and send all requests to displayAllFlashMessages() and ensure that all calls of that function deliver the data as an array. If those $name and type variables are relevant, pass them to displayAllFlashMessages().

huangapple
  • 本文由 发表于 2023年5月11日 06:38:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/76223013.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定