So my goal is to create a string of random letters, and the letters can be repeated in the string. So I thought I could be clever and do this:

$str = implode(
  array_fill(0,10,
    function(){ 
      $c='abcdefghijklmnopqrstuvwxyz';
      return (string)$c{rand(0,strlen($c)-1)};
    }
  )
);
echo $str;

But I am receiving the following error:

Catchable fatal error: Object of class Closure could not be converted to string in ...

This is literally the only thing in my script, so no, it's not something else. Now, the manual states 3rd arg description for array_fill is "Value to use for filling", and it's listed as accepting a mixed type. Now I know that "mixed" does not necessarily equate to "any" type, but it seems reasonable to me that that I should be able to use an anonymous function as a 3rd arg, as long as it returns a string, right? But apparently I can't do this..

So, I'm not necessarily asking why I can't do this; it very likely boils down to the powers-that-be simply not writing it into the code under the hood. But I guess I just wanted to double check that I did this code "right" in the sense that it "should" work if php allowed for it (but doesn't), vs. maybe I somehow messed up somewhere else?

有帮助吗?

解决方案

Without an explicit variant of the function, there is no reason to expect a function to execute your callback, rather than simply leaving it as a variable.

Let's break down the logic a bit:

// Declare the callback
$something = function(){ 
  $c='abcdefghijklmnopqrstuvwxyz';
  return (string)$c{rand(0,strlen($c)-1)};
}

Regardless of what this function does, we now have a variable which happens to be a Closure.

// Fill the array
$list = array_fill(0,10,$something);

The array is now full of 10 copies of $something. That happens to be 10 pointers to our Closure. There's no reason for PHP to think that that's not what you want.

// Join up the items in the array to make a string
$str = implode($list);

Now, implode() has to make a string, so it converts each item in the array it's given to a string before proceeding. For an object, it will try to call __toString() (or the equivalent "under the hood" for built-in objects), but Closure has no such method. This is where your error is coming from.

So, no, you haven't messed up exactly, but it's not reasonable to assume that PHP will execute a callback just because you know that's what you want.


As Mark Baker points out in a comment, you can use array_map to execute your callback; reusing $something from above, and breaking it down for clarity:

// Create 10 items, with nothing interesting in them
$list_of_nulls = array_fill(0, 10, null);

// Run the callback for each item of that list
// It will be given the current value each time, but ignore it
$list = array_map($something, $list_of_nulls);

// Now you have the list you wanted to join up
$str = implode($list);

Of course, you could also just run the function 10 times in a loop:

$str = '';
for ( $i=0; $i<10; $i++ ) {
    $str .= $something();
}

其他提示

This can be done with array_fill and array_map:

$number_of_items = 25;

$array = array_map(function() {
  // Your callback here
  return 'foo';
}, array_fill(0, $number_of_items, null));
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top