Strange behavior adding this object to this static array - php

At the moment I test with this piece of code:
<?php
class Alert {
private $type;
private $message;
public static $_alerts = array();
public function add($type, $message) {
$this->type = $type;
$this->message = $message;
self::$_alerts[] = $this;
}
}
$alert = new Alert();
$alert->add("warning", "test 1");
$alert->add("error", "test 2");
echo "<pre>";
print_r(Alert::$_alerts);
echo "</pre>";
But my results are not like expected:
Array
(
[0] => Alert Object
(
[type:Alert:private] => error
[message:Alert:private] => test 2
)
[1] => Alert Object
(
[type:Alert:private] => error
[message:Alert:private] => test 2
)
)
Why is my added object changed?
Test area: http://codepad.viper-7.com/6q2H2A

That's because your object (i.e. $this in internal context) will be copied by reference, not by value. To do copy by value, you'll need to do:
public function add($type, $message)
{
$this->type = $type;
$this->message = $message;
self::$_alerts[] = clone $this;
}
As an alternative, you'll need to instantiate (that is, for example, constructions like new self - but clone seems to be more flexible here) your object as many times as you'll wish to copy.
By the way, there's easy way to realize what's going on. Use var_dump() instead of print_r() - then you'll see that objects are actually same. Sample for your code (i.e. where copying is not fixed yet):
array(2) {
[0]=>
object(Alert)#1 (2) {
["type":"Alert":private]=>
string(5) "error"
["message":"Alert":private]=>
string(6) "test 2"
}
[1]=>
object(Alert)#1 (2) {
["type":"Alert":private]=>
string(5) "error"
["message":"Alert":private]=>
string(6) "test 2"
}
}
-as you can see, objects are same there.

You save 2 refferences to the same object in your $_alerts array. You need to create a new object for each alert or do something like this:
<?php
class Alert {
private $type;
private $message;
public static $_alerts = array();
private function __construct($type,$message){
$this->type=$type;
$this->message = $message;
}
public function getMessage(){
return $this->message;
}
public function getType(){
return $this->type;
}
public static function add($type, $message) {
self::$_alerts[] = new self($type,$message);
}
}
Alert::add("warning", "test 1");
Alert::add("error", "test 2");
echo "<pre>";
print_r(Alert::$_alerts);
echo "</pre>";

The problem you are seeing is because your code is changing the same object twice.
The first call, it will set the data "warning" and "test 1", and the second time it will overwrite these values.
You can solve this by creating a new instance of the object and adding the data:
$alert = new Alert();
$alert->add("warning", "test 1");
$alert2 = new Alert();
$alert2->add("error", "test 2");
This should give the following result:
Array
(
[0] => Alert Object
(
[type:Alert:private] => warning
[message:Alert:private] => test 1
)
[1] => Alert Object
(
[type:Alert:private] => error
[message:Alert:private] => test 2
)
)

Related

I need to implement the function which accepts color as a string parameter and return it as a json_encode

I want to get the function that can accept a string parameter and return it to json format.
for example if i call $ballcolor->getBall("orange");
then the output// should be:
{ "color":"orange", "ball": ["basketball"]}
and if a call does not have any color for that ball:
{ "color":"black", "ball": []}
class BallColor
{
private $ballcolor;
function BallColor($ballcolor)
{
$this->ballcolor = $ballcolor;
}
public function getBall($color)
{
return NULL;
}
}
$ballcolor = new BallColor(array(
"orange" => array("basketball"),
"white" => array("football")
));
echo $ballcolor->getBall("orange");
echo "\n";
echo $ballcolor->getBall("black");
Get the desired value out of $this->ballcolor after checking it's there, then build the array you need to return, then json_encode that:
class BallColor
{
private $ballcolor;
function __construct($ballcolor)
{
$this->ballcolor = $ballcolor;
}
public function getBall($color)
{
// condensed into oneliners:
if(isset($this->ballcolor[$color])) {
return json_encode(Array("color" => $color, "ball" => $this->ballcolor[$color]));
} else {
return json_encode(Array("color" => "black", "ball" => []));
}
}
}
$ballcolor = new BallColor(array(
"orange" => array("basketball"),
"white" => array("football")
));
echo $ballcolor->getBall("orange");
echo "\n";
echo $ballcolor->getBall("black");
Output:
{"color":"orange","ball":["basketball"]}
{"color":"black","ball":[]}
you should use
function __construct($ballcolor)
instead of
function BallColor($ballcolor)
as you constructor, unless your php version is old.

PHPUnit test doesn't 'go' into if conditional

public function test_cleansUpHouses()
{
$houseWithNoHP = new \DeadStreet\ValueObject\House\House();
$houseWithNoHP->setHitPoints(0);
$houseWithNoHP->setCurrentAttackers(1);
$houseWithHP = new \DeadStreet\ValueObject\House\House();
$houseWithHP->setCurrentAttackers(1);
$houseWithHPWasNotAttacked = new \DeadStreet\ValueObject\House\House();
$houseWithHPWasNotAttacked->setCurrentAttackers(1);
$houseCollection = new \DeadStreet\ValueObject\House\Collection(
[$houseWithNoHP, $houseWithHP, $houseWithHPWasNotAttacked]
);
$this->mockHouseModel->expects($this->at(0))
->method('hasBeenAttacked')
->with($houseWithNoHP)
->willReturn(true);
$this->mockHouseModel->expects($this->at(1))
->method('hasBeenAttacked')
->with($houseWithHP)
->willReturn(true);
$this->mockHouseModel->expects($this->at(2))
->method('hasBeenAttacked')
->with($houseWithHPWasNotAttacked)
->willReturn(false);
$this->mockHouseModel->expects($this->at(0))
->method('requiresDestroying')
->with($houseWithNoHP)
->willReturn(true);
$this->mockHouseModel->expects($this->at(1))
->method('requiresDestroying')
->with($houseWithHP)
->willReturn(false);
$expectedHouses = [$houseWithHP, $houseWithHPWasNotAttacked];
$cleanedUpHouses = $this->createObject()->cleanUpHouses($houseCollection);
$this->assertEquals($expectedHouses, $cleanedUpHouses->getHouses());
}
private function createObject()
{
return new Collection($this->mockHouseModel);
}
And here's the model under test
public function cleanUpHouses(\DeadStreet\ValueObject\House\Collection $collection)
{
foreach($collection->getHouses() as $key => $house) {
if(!$this->houseModel->hasBeenAttacked($house)) {
break;
}
if($this->houseModel->requiresDestroying($house)) {
unset($collection->getHouses()[$key]);
}
}
return $collection;
}
However, this line if($this->houseModel->requiresDestroying($house)) { is never being returned as true, even though I have the line
$this->mockHouseModel->expects($this->at(0))
->method('requiresDestroying')
->with($houseWithNoHP)
->willReturn(true);
The error I'm getting.
1) DeadStreet\Model\House\Collection_Test::test_cleansUpHouses
Failed asserting that two arrays are equal.
--- Expected
+++ Actual
## ##
Array (
0 => DeadStreet\ValueObject\House\House Object (...)
1 => DeadStreet\ValueObject\House\House Object (...)
+ 2 => DeadStreet\ValueObject\House\House Object (...)
)
Are you sure the code is working correctly?
This line
unset($collection->getHouses()[$key]);
uses a copy of your array to execute an unset on it.
Example:
class Test
{
private $array = array("a" => 1, "b" => 2);
public function unsetArray()
{
unset($this->getArray["a"]);
}
public function getArray()
{
return $this->array;
}
}
$test = new Test();
$test->unsetArray();
The method unsetArray always resets on a copy here, not the actual array. If you want something like that. You have to use the actual array like this.
public function unsetArray()
{
unset($this->array["a"]);
}

PHP SoapClient missing data

I'm using a SoapClient (zend2), but for some reasons, can't get complete data answer
$client = new \SoapClient($host);
$result = $client->getInvoice();
$result var_dump:
["ListInvoiceResult"] => object(stdClass)#282 (4) {
["Status"] => int(1)
["ErrorCode"] => NULL
["ErrorMessage"] => string(0) ""
["Invoice"] => array(1436) {
[0] => object(stdClass)#283 (3) {
["ID"] => int(12741)
["Date"] => string(10) "2011.01.31"
["DateSales"] => string(10) "2011.01.31"
}
Above object missing a variable InvoiceNumber
But when I call __getLastResponse method , I've recieved complete data with InvoiceNumber
<p1:Invoice>
<p1:ID>12741</p1:ID>
<p1:InvoiceNumber>1|FA|2011|00633</p1:InvoiceNumber>
<p1:Date>2011.01.31</p1:Date>
<p1:DateSales>2011.01.31</p1:DateSales>
</p1:Invoice>
Hmmm. Looks strange. But all other methods returns complete data, even variable Invoice Number..
I think you should try using the classmap option in SoapClient or check you mapped classes, for instance:
class MyBook {
public $title;
public $author;
}
$server = new SoapClient("books.wsdl", array('classmap' => array('book' => "MyBook")));
In your case you should model ListInvoiceResult and Invoice class for instance:
class WS_ListInvoiceResult {
public $Status;
public $ErrorCode;
public $ErrorMessage;
public $Invoice;
}
class WS_Invoice {
public $ID;
public $Date;
public $DateSales;
public $InvoiceNumber;
}
And connect to soap api as such:
$server = new SoapClient("wsdl path", array('classmap' => array("ListInvoiceResult" => "WS_ListInvoiceResult", "Invoice" => "WS_Invoice")));
If this doesn't help try checking your WSDL, though based on the response it appears to be OK.

how to save many objects in a $session array variable

I'm new in the object oriented programming so this question might be silly...
I've created my class in a separate file called classProduct.php
<?php
class product{
public $prodId;
public $prodName;
public $prodPrice;
public function __construct($prodId,$prodName,$prodPrice){
$this->prodId = $prodId;
$this->prodName=$prodName;
$this->prodPrice=$prodPrice;
}
public function get_prodId(){
return $this->prodId;
}
public function get_prodName(){
return $this->prodName;
}
public function get_prodPrice(){
return $this->prodPrice;
}
}
?>
Then I tried to create a new object in a $_SESSION variable. This happens in another file called dailySales.php where I include the previous file using:
include_once("classProduct.php");
What I want to do is to save in $_SESSION['myItems'] each new object. I am trying something like:
$newItem= new product($var,$var,$var);
$_SESSION['myItems']=array($newItem); // I believe here is where I do it wrong
Every time the buyer chooses one more products, the pages reloads (with ajax). When I echo or var_dump the $_SESSION['myItems'] I only get the last object. What do I need to change to get it working correctly?
Of course I do need the object so I can easily remove a product from the shopping cart if
'Delete' is pressed.
This is working for me locally.
Define your items session variable as an array, then push them into the variable using array_push
class product {
public $prodId;
public $prodName;
public $prodPrice;
public function __construct($prodId, $prodName, $prodPrice) {
$this->prodId = $prodId;
$this->prodName = $prodName;
$this->prodPrice = $prodPrice;
}
public function get_prodId() {
return $this->prodId;
}
public function get_prodName() {
return $this->prodName;
}
public function get_prodPrice() {
return $this->prodPrice;
}
}
Then use it like so:
$product = new product(1, "test", 23);
$product2 = new product(2, "test2", 43);
$_SESSION['items'] = array();
array_push($_SESSION['items'], $product, $product2);
echo '<pre>';
print_r($_SESSION['items']);
echo '</pre>';
This is the output of print_r()
Array
(
[0] => product Object
(
[prodId] => 1
[prodName] => test
[prodPrice] => 23
)
[1] => product Object
(
[prodId] => 2
[prodName] => test2
[prodPrice] => 43
)
)

empty() does not work when passing data from an object. Why?

I just discovered that empty() does not work when passing data from an object. Why is that?
This is my code:
// This works
$description = $store->description;
if (!empty($description) )
echo $description;
//This is not working
if (!empty($store->description) )
echo $store->description;
UPDATE
Added extra code for context.
// At the top of my PHP file I have this code
$store = Factory::new_store_obj($id);
// To controll that I got content, I can test by printing object
echo '<pre>';
print_r($store);
echo '</pre>';
//output
Store Object
(
[data:Store:private] => Array
(
[name] => Lacrosse
[street1] => Bygdøy Allé 54
[street2] =>
[zipcode] => 0265
[city] => Oslo
[country] => Norway
[phone] => 22441100
[fax] =>
[email] =>
[opening_hours] =>
[keywords] =>
[description] => Lacrosse er en bla bla bla...
)
)
You should read the docs for empty(). There is an explanation of why empty might fail in the comments.
For example you will get this error if description is a private property, you have set up a magic __get function without the magic __isset function.
So this will fail:
class MyClass {
private $foo = 'foo';
public function __get($var) { return $this->$var; }
}
$inst = new MyClass;
if(empty($inst->foo))
{
print "empty";
}
else
{
print "full";
}
and this will succeed:
class MyClass {
private $foo = 'foo';
public function __get($var) { return $this->$var; }
public function __isset($var) { return isset($this->$var); }
}
$inst = new MyClass;
if(empty($inst->foo))
{
print "empty";
}
else
{
print "full";
}
input:
<?php
$item->description = "testme";
$description = $item->description;
if (!empty($description) )
echo $description;
//This is not working
if (!empty($item->description) )
echo $item->description;
?>
output
testmetestme
conclusion: it works
I tried this:
class test {
private $var = '';
public function doit() {
echo (empty($this->var)) ? 'empty' : 'not';
echo '<br>';
var_dump($this->var);
}
}
$t = new test;
$t->doit();
It outputs: empty, string(0) "". This means that it works. Try it your self if you want. It must be the class context not working.

Categories