Returning a object gets true instead of beeing an object

Viewed 31

I am working on a PHP script for placing small boxes (simple rectangles) in a bigger box. For this I ported a Javascript version of the code to PHP.

<?php

class Packer
{
   private $box;

   /**
    * Packer constructor.
    * @param int $width
    * @param int $height
    */
   public function __construct(int $width, int $height)
   {
       $this->box = new Box($width, $height);
   }

   /**
    * @param $blocks
    */
   public function fitBlocksIntoBox($blocks)
   {
       for ($n = 0; $n < sizeof($blocks); $n++) {
           $block = $blocks[$n];
           $node = $this->findNode($this->box, $block->width, $block->height);
           if ($node) {
               $block->fitsInBox = $this->splitNode($node, $block->width, $block->height);
           }
       }
   }

   /**
    * @param $box
    * @param $width
    * @param $height
    * @return Box|null
    */
   private function findNode($box, $width, $height)
   {
       if ($box->used) {
           return $this->findNode($box->right, $width, $height) || $this->findNode($box->down, $width, $height);
       } else if (($width <= $box->width) && ($height <= $box->height)) {
           return $box;
       } else {
           return null;
       }
   }

   /**
    * @param $node
    * @param $width
    * @param $height
    * @return mixed
    */
   private function splitNode($node, $width, $height)
   {
       $node->used = true;

       $bW = $node->width;
       $bH = $node->height - $height;
       $bX = $node->x;
       $bY = $node->y + $height;
       $node->down = new Box($bW, $bH, $bX, $bY);

       $bW = $node->width - $width;
       $bH = $node->height;
       $bX = $node->x + $width;
       $bY = $node->y;
       $node->right = new Box($bW, $bH, $bX, $bY);
       return $node;
   }

}

class Block
{
   public $width;
   public $height;
   public $fitsInBox;

   public function __construct($width, $height) {
       $this->width = $width;
       $this->height = $height;
   }
}

class Box
{
   public $x;
   public $y;
   public $width;
   public $height;
   public $used;
   public $down;
   public $right;

   public function __construct($width, $height, $x = 0, $y = 0) {
       $this->x = $x;
       $this->y = $y;
       $this->width = $width;
       $this->height = $height;
       $this->used = false;
       $this->right = null;
       $this->down = null;
   }
}

I run the script like this.

<?php
require_once('Packer.php');
require_once('Box.php');
require_once('Block.php');

$blocks = [
    new Block(100, 100),
    new Block(50, 50),
    new Block(50, 50),
    new Block(40, 30)
];

$packer = new Packer(900, 1200);
$packer->fitBlocksIntoBox($blocks);

In the first loop, the script does exactly what I expect. It places the first block in the box and calculate for down and right two new boxes. The second loop creates the problem, which I do not understand why it will happen.

The function findNode will check if the box is already in use. If so, it will check if box-right or box-down are used and calls itself with this box. This works. In the next call of this function it detects the box is not used and the block will fit in and it returns this box. The result will be stored in $node in function fitBlocksIntoBox and now it is no Box anymore, the result is true.

Debug first loop

enter image description here

Debug second loop - return from findNode

enter image description here

Debug second loop - fitBlocksIntoBox if($node)...

enter image description here

I run the script through XDebug and it shows me, that findNode() returns the Box as expected. Hopefully, someone has a hint for me, what I am doing wrong here. Thanks, Timo

1 Answers

Use ?: instead of ||.

|| doesn't work the same way in PHP that it does in JavaScript.

With || the two ->findNode() calls are evaluated to a boolean, as you're seeing.

The ?: operator will return the first value if it is "truthy" or the second value if not.

Related