[Solved] Can not use function return value in write context

Hi all

Trying to add a sort function into an existing snippet, though keeps saying “Fatal error: Can’t use function return value in write context in… line 88”:

     function sortFunction( $a, $b ) {
        return strtotime($a["last_modified"]) - strtotime($b["last_modified"]);
      }

    $children = $topPage->getChildren(null,true);
          if (!empty($children)) {
            //line 88
            foreach($children as usort($child, "sortFunction")) { ...

Any ideas?

Thanks, Barry

Hi Barry,

You can’t use a function as part of the foreach statement - what you have to do instead is get the value and then sort it, like this:

foreach ($children as &$child) {
    usort($child, 'sortFunction');
}

Note that I’ve assumed you want to sort the child arrays in-place, so putting an ampersand infront of the variable name causes PHP to reference the original child array rather than making a copy.

WARNING
usort() expects parameter 1 to be array, object given…

It then prints full array list of navigation table for each article shown

Function: usort(Array ( [0] => Navigation_PageItem Object ( [page_id]… [last_modified] => 2014-12-02 18:00:24…

[last_modified] => 2014-12-02 18:00:24
This is the column I’m trying to sort by.

?

Thanks fretburner

Could you do a var_dump of $children and post it here please?

Sure, he is the dump this is with only one article showing.
Hope this helps.

array(1) { [0]=> object(Navigation_PageItem)#14 (33) { ["page_id"]=> string(2) "33" ["location_type"]=> string(8) "WORKAREA" ["location_name"]=> string(6) "htdocs" ["output"]=> string(3) "web" ["parent_page_id"]=> string(2) "22" ["language"]=> string(2) "fr" ["precedence"]=> string(1) "1" ["file_name"]=> string(36) "single-page.php" ["target"]=> string(5) "_self" ["title"]=> string(32) "Single page title" ["title_alt"]=> string(32) "Single page" ["is_ssl"]=> bool(false) ["is_auth"]=> bool(false) ["is_hidden"]=> bool(true) ["forward_url"]=> string(0) "" ["ext_column_1"]=> string(4) "pink" ["ext_column_2"]=> string(47) "/static/media/images/example.jpg" ["ext_column_3"]=> string(40) "Some other title" ["ext_column_4"]=> string(0) "" ["ext_column_5"]=> string(0) "" ["l"]=> string(2) "15" ["r"]=> string(2) "16" ["file_path"]=> string(63) "single-page.php" ["level"]=> string(1) "2" ["has_children"]=> string(1) "0" ["priority"]=> string(3) "0.5" ["changefreq"]=> string(6) "weekly" ["noindex"]=> string(1) "0" ["last_modified"]=> string(19) "2014-12-08 11:45:18" ["url"]=> string(63) "/single-page.php" ["isActive"]=> bool(false) ["isCurrent"]=> bool(false) ["childs"]=> array(0) { } } }

Thanks, Barry

OK, so not all children are arrays, so you’re going to need to check before calling usort - you can do this with the is_array function.

Do you have an example how this will work with my code?

foreach ($children as &$child) {
    if (is_array($child)) {
        usort($child, 'sortFunction');
    }
}

Trying to add a sort function into an existing snippet, though keeps
saying “Fatal error: Can’t use function return value in write context
in… line 88”:

usort, like most PHP array manipulation functions, receives the array to work upon by reference, and returns boolean to indicate if it successfully performed it’s operation. That isn’t the cause of the error here, but that’s your first misconception on how the function works.

You can’t use a function as part of the foreach statement

That isn’t true. You can, what you can’t do is write to it with foreach, which is what the OP’s code is trying to do and what is kicking the error. If the function returns an array it’s perfectly legal to iterate off the return, for example,

foreach (glob('./*.php') as $file) {}

This is only safe if you are absolutely certain the function will either return an array, or throw an exception. Returning an empty array will result in the iteration not being performed. Glob is an off the top of my head example and isn’t an ideal example because it returns “false” if the file search pattern doesn’t match anything.

The part of the foreach to the right of “as” is being written to, and you can’t write to functions. It’s just as illegal as this

usort($child, 'sortFunction') = $vars;

If I understand your intent correctly you’re using the wrong function. usort won’t help - use array_multisort. You also need to normalize the return of that function to be arrays only instead of a mix of arrays and objects. Finally, if this is coming out of a database it will be FAR faster to sort at query time than in PHP.

Thanks guys.
Are you saying that fretburners example won’t work?
And instead I should use:

foreach ($children as &$child) {
if (is_array($child)) {
array_multisort($child, 'sortFunction');
}
}

Some good information here thanks, though starting to get a bit heavy for a basic sort :smile:
As things stand I don’t have access to the database logic as everything is included from the CMS, else I would do the sorting at database level, as you sty, much better.

Barry

No. Since it’s a slow day at work for me, here…

/*
 * First get the pages.
 */
$pages = $topPage->getChildren(null, true);

/*
 * Extract the last Modified Column
 */
$lastModified = array();

foreach ($pages as $key => $row) {
    $modified[$key] = $row->last_modified;
}

/*
 * Now sort the pages array on that column. That each row is an object won't matter.
 */
array_multisort($modified, SORT_STRING, SORT_DESC, $pages);

You don’t need strtotime because the lastModified value is already in the correct format to be string sorted. If you need ascending order use SORT_ASC. Since array_multisort receives by referrence $pages will be in the desired order immediately after this code executes.

Ok, getting a little confusing now, heres goes, my full code:

 function sortFunction( $a, $b ) {
            return strtotime($a["last_modified"]) - strtotime($b["last_modified"]);
          }

      // get all pages
      $pages = new TFW_Navigation($pageNav);
      $pages = $pages->getNavigation();
        foreach ($pages as $index => $topPage)
      {
      
      // First get the pages.
      $pages = $topPage->getChildren(null, true);

      //Extract the last Modified Column
      $lastModified = array();

      foreach ($pages as $key => $row) {
          $modified[$key] = $row->last_modified;

Errors:

Undefined variable: child
Trying to get property of non-object

<article class="<?=$child->ext_column_1 ?>">
     <a href="<?= $child->url ?>" class='article-border'>
        <img src="<?=$child->ext_column_2 ?>" alt="">
          <header>
              <h3>
                  <?= $child->ext_column_3 ?>
              </h3>
          </header>
          <footer>
              <p>
                <?php echo date("d F Y", strtotime($child->last_modified))."<span class='sprite article-link ".$child->ext_column_1."'></span>" ?>

              </p>
          </footer>
      </a>
  </article>

Help much appreciated thanks.

After you sort the pages you’re going to need to start a foreach loop to iterate over them for each article template you echo out. The loop will be

foreach ($pages as $child)

Beyond that, you need to work this out on your own because I fear further help will do more harm than good by not letting you learn this for yourself. The sortFunction you made isn’t needed anymore and can be deleted.

Thanks Michael

Ha correct, causing some headaches already :smile:
I had everything working previous, I needed to change $child->column to $row->column… then everything worked. I’ve now changed something and back to square one.

Though as you say, good learning curve a suppose.

I’m also needing a limit on the articles returned, though might try some javascript for that, though is it hard to add a limit?

Cheers, Barry

array_slice

1 Like

Hi

No errors, but why dosen’t this work when I run it:

foreach($children as $child) {
          array_slice($children, 1, 2);

I still get about 40 items returned, it does nothing.

And if I try:

foreach($children as $child) {
              array_slice($child, 1, 2);

array_slice() expects parameter 1 to be array, object given


Also with the multisort, been trying everything, just can’t get anything to work.

WARNING
array_multisort() [function.array-multisort]: Array sizes are inconsistent…

$pages = new TFW_Navigation($pageNav);
        $pages = $pages->getNavigation();
          foreach ($pages as $index => $topPage)
        {
        $children = $topPage->getChildren(null,true);
        
        //Extract the last Modified Column
        $lastModified = array();

        foreach ($pages as $key => $row) {
            $modified[$key] = $row->last_modified;

        //Now sort the pages array on that column.
        array_multisort($modified, SORT_STRING, SORT_DESC, $pages);
        
        if (!empty($children)) {
        foreach($children as $child) {

I don’t thing it can get any worse ha :smile:
Been at this and other code for nights… hours, no results.

Barry

Instead of a trial and error approach and hoping the script will work try calling this function wherever errors or warnings appear:

function vd($val)
{
echo '<pre>';
var_dump( $val);
echo '</pre>';
die;
}

Tapped laboriously from a tablet :frowning:

:smile: This is what I’ve been doing all weekend ha
So how do I attached this to my code to find the errors?

Is this what you mean, if this is/was giving the error?

array_slice(vd($children, 1, 2));

No rush if you’re on a tablet :sunny:
And what about the errors themselves, can you see any problems with this, a fix?

Thanks, Barry

Try this:

foreach($children as $child) {
 vd( $child );
 array_slice( $child,1,2);

Thanks John,

I’m just trying that now…
Though, I have just tried:

array_slice(vd($children, 1, 2));

Which prints all the xml code for 9 Navigation_PageItems, so what is that telling us?

array(9) {
  [0]=>
  object(Navigation_PageItem)#32 (33) {
    ["page_id"]=>
    string(2) "28"
    ["location_type"]=>
    string(8) "WORKAREA"
    ["location_name"]=>
    string(6) "htdocs"
    ["output"]=>
    string(3) "web"
    ["parent_page_id"]=>
    string(2) "20"
    ["language"]=>
    string(2) "fr"
    ["precedence"]=>
    string(1) "1"
    ["file_name"]=>
....
 [1]=>
  object(Navigation_PageItem)#33 (33) {
    ["page_id"]=>
    string(2) "31"
....

Thanks, get back 1 minute just trying the other.

Update

foreach($children as $child) {
vd( $child );
array_slice( $child,1,2);

object(Navigation_PageItem)#32 (33) {
  ["page_id"]=>
  string(2) "28"
  ["location_type"]=>
  string(8) "WORKAREA"
  ["location_name"]=>
  string(6) "htdocs"
  ["output"]=>
  string(3) "web"
  ["parent_page_id"]=>
  string(2) "20"
  ["language"]=>
  string(2) "fr"
  ["precedence"]=>
  string(1) "1"
  ["file_name"]=>
  ...

This is showing the object for the single article, the current page. Just one item.

What I’m trying to do is show a list of related articles below this page/current article, if that makes sense. So with what we can see here, it seems right, I think. What do you make of it?

Barry