views:

1449

answers:

3

Hi

In PHP, I know there is no official way to delete items once they have been put into an array. But there must be a "best-method" solution to my problem. I believe this may lie in the array_filter function.

Essentially, I have a shopping cart object that stores items in a hashtable. Imagine you can only ever buy one of any item at a time.

I do

add_item(1);
add_item(2);
remove_item(1);

get_count() still returns 2.

var $items;


function add_item($id) {
 $this->items[$id] = new myitem($id);
}

function remove_item($id) {
 if ($this->items[$id]) {
  $this->items[$id] = false;
  return true;
 } else { 
  return false;
 }
}


function get_count() {
 return count($this->items);
}

What do people think is the best method to use in get_count? I can't figure out the best way to use array_filter that simply doesn't return false values (without writing a seperate callback).

Thanks :)

+5  A: 
if ($this->items[$id]) {

May return a warning, should use array_key_exists or isset.

unset() seems cleaner than assigning false when removing an item (will also get rid of your count problem).

Mario
+5  A: 

No official way? Sure there is! Unset!

<?php

class foo
{
    var $items = array();


    function add_item($id) {
            $this->items[$id] = new myitem($id);
    }

    function remove_item($id)
    {
        unset( $this->items[$id] );

    }


    function get_count() {
            return count($this->items);
    }
}

class myitem
{
    function myitem( $id )
    {
     // nothing
    }
}

$f = new foo();

$f->add_item( 1 );
$f->add_item( 2 );

$f->remove_item( 1 );

echo $f->get_count();

Also, is this PHP4? Because if not, you should look into some of the SPL stuff like ArrayObject or at least the the Countable and ArrayAccess interfaces.

EDIT

Here's a version using the interfaces directly

<?php

class foo implements ArrayAccess, Countable
{
    protected $items = array();

    public function offsetExists( $offset )
    {
     return isset( $this->items );
    }

    public function offsetGet( $offset )
    {
     return $this->items[$offset];
    }

    public function offsetSet( $offset, $value )
    {
     $this->items[$offset] = $value;
    }

    public function offsetUnset( $offset )
    {
     unset( $this->items[$offset] );
    }

    public function count()
    {
     return count( $this->items );
    }

    public function addItem( $id )
    {
     $this[$id] = new myitem( $id );
    }
}

class myitem
{
    public function __construct( $id )
    {
     // nothing
    }
}

$f = new foo();

$f->addItem( 1 );
$f->addItem( 2 );
unset( $f[1] );

echo count( $f );

And here's a version as an implementation of ArrayObject

<?php

class foo extends ArrayObject
{
    public function addItem( $id )
    {
     $this[$id] = new myitem( $id );
    }
}

class myitem
{
    public function __construct( $id )
    {
     // nothing
    }
}

$f = new foo();

$f->addItem( 1 );
$f->addItem( 2 );
unset( $f[1] );

echo count( $f );
Peter Bailey
Get rid of the isset condition ;)
Mario
Oh, I guess it's not needed. I didn't test the code, but I guess it doesn't throw a warning with unset() after all.
Peter Bailey
+3  A: 

+1 to both Peter's and Mario's answers: using unset() is the correct way to remove items from an array.

I just wanted to leave a note to explain why your method wasn't working. Using count() will count the number of values in an array. false, though you could imagine it as meaning "nothing", is still actually a value. Typically if you want to actually specify "no value" then use null.

You can also unset an array element by setting it to null, though look at the code below to see the difference.

$x = array("a", "b", "c");

var_dump(isset($x[0]));   // bool(true)
var_dump(isset($x[1]));   // bool(true)
var_dump(isset($x[2]));   // bool(true)
echo count($x);           // 3

$x[2] = null;
var_dump(isset($x[2]));   // bool(false) -- the value is not set any longer
echo count($x);           // 3  -- but it doesn't remove it from the array

unset($x[1]);
var_dump(isset($x[1]));   // bool(false)
echo count($x);           // 2
nickf