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
)
)
Related
I've a university project in which I've to print the relations between students in different classes level by level. The idea is if we have John and Kris studying in the same class they are friends of first level, if Kris studies with Math in same class then John and Math are friends of second level. I researched the problem and I found algorithms like this, but my main problem is that I use objects as input data :
<?php
class Student {
private $id = null;
private $classes = [];
public function __construct($id) {
$this->id = $id;
}
public function getId() {
return $this->id;
}
public function getClasses() {
return $this->classes;
}
public function addClass(UClass $class) {
array_push($this->classes, $class);
}
}
class UClass {
private $id = null;
private $students= [];
public function __construct($id) {
$this->id = $id;
}
public function getId() {
return $this->id;
}
public function getStudents() {
return $this->students;
}
public function addStudent(Student $student) {
array_push($this->students, $student);
$student->addClass($this);
}
}
function getRelations(Student $start_student, &$tree = array(), $level = 2, &$visited) {
foreach ($start_student>Classes() as $class) {
foreach ($class->Students() as $student) {
if($start_student->getId() != $student->getId() && !is_int(array_search($student->getId(), $visited))) {
$tree[$level][] = $student->getId();
array_push($visited, $student->getId());
getRelations($student, $tree, $level+1, $visited);
}
}
}
}
$class = new UClass(1);
$class2 = new UClass(2);
$class3 = new UClass(3);
$student = new Student(1);
$student2 = new Student(2);
$student3 = new Student(3);
$student4 = new Student(4);
$student5 = new Student(5);
$student6 = new Student(6);
$class->addStudent($student);
$class->addStudent($student2);
$class->addStudent($student4);
$class2->addStudentr($student2);
$class2->addStudent($student4);
$class2->addStudent($student5);
$class3->addStudent($student4);
$class3->addStudent($student5);
$class3->addStudent($student6);
$tree[1][] = $student->getId();
$visited = array($student->getId());
getRelations($student, $tree, 2, $visited);
print_r($tree);
I'm stuck at writing getRelations() function that should create an array that is something like
Array ( [1] => Array ( [0] => 1 ) [2] => Array ( [0] => 2 [1] => 4 ) [3] => Array ( [0] => 5 [1] => 6 ) )
but I can't get the recursion right(or probably the whole algorithm). Any help will be greatly appreciated.
The logic in your recursive procedure is not correct. Example:
Say you enter the procedure for some level A and there are actually 2 students to be found for a connection at that level.
You handle the first, assign the correct level A, mark him as "visited".
Then, before getting to the second, you process level A+1 for the first student. Somewhere in his "chain" you may also find the second student that was waiting to get handled at level A. However, he now gets assigned some higher level A+n, and is then marked as visited.
Next, when the recursion for student1 is finished, you continue with the second. However, he has already been "visited"...
(By the way, I do not quite understand (but my php is weak...) why your first invocation of GetRelations specifies level=2.)
Anyway, to get your logic right there's no need for recursion.
Add a property "level" to each student. Put all students also in an overall collection "population".
Then, for a chosen "startStudent", give himself level=0, all other students level=-1.
Iterate levels and try to fill in friendship levels until there's nothing left to do. My php is virtually non-existent, so I try some pseudo-code.
for(int level=0; ; level++) // no terminating condition here
{
int countHandled = 0;
for each (student in population.students)
{
if (student.level==level)
{
for each (class in student.classes)
{
for each (student in class.students)
{
if(student.level==-1)
{
student.level = level+1;
countHandled++;
}
}
}
}
}
if(countHandled==0)
break;
}
Hope this helps you out. Of course, you still have to fill in the tree/print stuff; my contribution only addresses the logic of assigning levels correctly.
I come up with that function(not sure if it's the best solution, but it works with the class objects)
function print_students(Student $start_student, &$tree = array(), $lvl = 1) {
if (!$start_student) {
return;
}
$tree[$lvl][] = $start_student->getId();
$q = array();
array_push($q, $start_student);
$visited = array($start_student->getId());
while (count($q)) {
$lvl++;
$lvl_students = array();
foreach ($q as $current_student) {
foreach ($current_student->getClasses() as $class) {
foreach ($class->getStudents() as $student) {
if (!is_int(array_search($student->getId(), $visited))) {
array_push($lvl_students, $student);
array_push($visited, $student->getId());
$tree[$lvl][] = $student->getId();
}
}
}
}
$q = $lvl_students;
}
}
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
)
)
I needed to select a controller in CakePHP 2.4 and display all the functions written in it. I found how to list controllers from this question & answer thread on Stack Overflow but what I need now is given a specific controller I need to get the list of all functions it contains.
Here what i have done
public function getControllerList() {
$controllerClasses = App::objects('controller');
pr($controllerClasses);
foreach($controllerClasses as $controller) {
$actions = get_class_methods($controller);
echo '<br/>';echo '<br/>';
pr($actions);
}
}
pr($controllerClasses); gives me list of controllers as follows
Array
(
[0] => AppController
[1] => BoardsController
[2] => TeamsController
[3] => TypesController
[4] => UsersController
)
however pr($actions); nothing... :(
here you go the final working snippet the way i needed
http://www.cleverweb.nl/cakephp/list-all-controllers-in-cakephp-2/
public function getControllerList() {
$controllerClasses = App::objects('controller');
foreach ($controllerClasses as $controller) {
if ($controller != 'AppController') {
// Load the controller
App::import('Controller', str_replace('Controller', '', $controller));
// Load its methods / actions
$actionMethods = get_class_methods($controller);
foreach ($actionMethods as $key => $method) {
if ($method{0} == '_') {
unset($actionMethods[$key]);
}
}
// Load the ApplicationController (if there is one)
App::import('Controller', 'AppController');
$parentActions = get_class_methods('AppController');
$controllers[$controller] = array_diff($actionMethods, $parentActions);
}
}
return $controllers;
}
Something like this should do the trick:
https://github.com/dereuromark/cakephp-sandbox/blob/master/Plugin/Sandbox/Controller/SandboxAppController.php#L12
It basically uses a very basic PHP function:
$actions = get_class_methods($Controller);
Then get parent methods:
$parentMethods = get_class_methods(get_parent_class($Controller));
Finally, using array_diff you get the actual actions in that controller:
$actions = array_diff($actions, $parentMethods);
Then you can still filter out unwanted actions.
I have an Object that needs to access a previously declared array in my statistics. I can of course create the entire array inside of the object, but since multiple objects use the exact same array there is no reason to clog up memory or time by making a call to the Database to create the same array every time I create a new object.
So, I understood that Objects cannot access global variables, but is there any work-around to access an external Array from within the object?
example Code:
global $stats = array();
$stats[1]['value']= 10;
$stats[1]['value1'] =2;
$stats[2]['value']= 12;
$stats[2]['value1'] =1;
class Obj() {
private $valueA;
private $valueB;
function __construct($user) {
//access Database lets call $SQL;
$valueA = SQL->value;
}
function showA() {
return ( $valueA * $stats[1]['value1']) + $stats[1]['value'];
}
}
Yes how about changing your class to look like this:
class Obj() {
private $valueA;
private $valueB;
private $stats;
function __construct($user, $stats) {
$this->stats = $stats;
//access Database lets call $SQL;
$valueA = SQL->value * $this->stats[1]['value1'] + $this->stats[1]['value'];
$valueB = SQL->value * $this->stats[2]['value1'] + $this->stats[2]['value'];
}
function showA() {
return $valueA;
}
}
You than just pass $stats to the object at instantiation. Or if you don't want it in the constructor, just make a setStats($stats) method that does the same.
I'll tell you three ways to do this:
pass the array into the constructor of the class. e.g.: $myObject =
new Obj( $stats );
make a class that serves up the $stats array: $stats = new Stats(); $statsArray = $stats->getStats();
use the term global inside of a public method in your class itself (not construct) to get that variable: 3:
function() somePublicMethod() {
global $stats;
$valueA = SQL->value * $stats[1]['value1'] + $stats[1]['value'];
$valueB = SQL->value * $stats[2]['value1'] + $stats[2]['value'];
}
You can access variables from within a class, i.e.
$stats[1]['value']= 10;
$stats[1]['value1'] =2;
$stats[2]['value']= 12;
$stats[2]['value1'] =1;
class Obj {
var $myStats;
function __construct() {
global $stats;
$this->myStats= $stats;
print_r($this->myStats);
}
}
$obj=new Obj; // Array ( [1] => Array ( [value] => 10 [value1] => 2 ) [2] => Array ( [value] => 12 [value1] => 1 ) )
DEMO.
Thanks to Mike, Sheikh and Kristian,
I can't in all Faith give a tick to your answers, because your words did not help me to understand the answer, Putting 'global $stats;' into the class results in an Error which I pointed out in my responses. but I will 'up' your scores when I permission from the site to do so.
For anyone looking for the answer to this, a Reminder, the key point is not to store the entire Array in the class, creating a huge waste of memory. The Key point is to gain access to the Variable which exists outside of the class.
While adding access to the global $stats by including it in the functions of the class, does produce the required results, It still requires that the Data is being stored in the class, which is again, against the point. Sorry I wasn't clear on this from the very beginning.
Instead:
example Code:
function showA(&$stats) {
return ( $valueA * $stats[1]['value1']) + $stats[1]['value'];
}
}
This, if I understand correctly, will use the pointer to the $stats variable, only within the scope of returning the $valueA after it has been modified using the stats array. not copying the entire array into another memory location, nor the class.
I'm creating a forum, and I want to keep track of which threads have been updated since the user last visited. So I have an array that I keep in $_SESSION that is basically structured as [$boardid][$threadid] = 1. If the threadid and boardid are set, then the thread has not been read and the board contains unread threads. When a user views a thread, I just unset() the appropriate board and thread id. However, I've having problems with getting unset to work with arrays like this.
Firstly, I have a session class to make handling session data a little nicer
class Session {
private $_namespace;
public function __construct($namespace = '_default') {
$this->_namespace = $namespace;
}
/**
* Erase all variables in the namespace
*/
public function clear() {
unset($_SESSION[$this->_namespace]);
}
public function __set($name, $value) {
$_SESSION[$this->_namespace][$name] = $value;
}
public function __get($name) {
if(isset($_SESSION[$this->_namespace]) && array_key_exists($name, $_SESSION[$this->_namespace])) {
return $_SESSION[$this->_namespace][$name];
}
return null;
}
public function __isset($name) {
return isset($_SESSION[$this->_namespace][$name]);
}
public function __unset($name) {
unset($_SESSION[$this->_namespace][$name]);
}
};
Then I have a CurrentUser class representing the current user. The CurrentUser class has a member named _data which is-a Session object. In the CurrentUser class I override the __get and __set methods to use the _data member.
public function __set($name, $value) {
$this->_data->$name = $value;
}
public function __isset($name) {
return isset($this->_data->$name);
}
public function __get($name) {
if(isset($this->_data->$name)) {
return $this->_data->$name;
}
return null;
}
Now to keep track of which threads have been unread, I fetch all threads whose date is >= the user's last_seen date. I also have methods to remove board and threads from the array.
public function buildUnreadList($since) {
// Build a "new since last visit" list
$forumModel = new Model_Forum();
$newThreads = $forumModel->fetchThreadsSinceDate($since);
foreach($newThreads as $thread) {
$tmp =& $this->unreadThreadsList;
$tmp[$thread['board']][$thread['id']] = 1;
}
}
public function removeThreadFromUnreadList($boardid, $threadid) {
$threads =& $this->unreadThreadsList;
unset($threads[$boardid][$threadid]);
}
public function removeBoardFromUnreadList($boardid) {
$threads =& $this->_data->unreadThreadsList;
unset($threads[$boardid]);
}
This is where I'm running into problems. I'm getting a Indirect modification of overloaded property Session::$unreadThreadsList has no effect error on $threads =& $this->_data->unreadThreadsList; How can I either fix this problem or design a better solution? I thought about creating a class that keeps track of the array so I don't have to have an array of arrays of arrays of arrays, but I'm not certain on persisting objects and creating an object just to manage an array feels really dirty to me.
Sorry if I'm a little bit off base; I'm trying to understand how the variables are being used (as their initialization is not shown). So $this->unreadThreadsList is an array where the indices (if value set to 1). Why not set everything directly?
Looking at what you're doing, here is an idea I had. It does the same thing but just does some extra checking on $this->unreadThreadsList and it accesses the variable directly.
Assuming I figured out the array structure properly, this should work.
public function buildUnreadList($since) {
// Build a "new since last visit" list
$forumModel = new Model_Forum;
$newThreads = $forumModel->fetchThreadsSinceDate($since);
foreach($newThread as $thread)
{
// Avoid an error if no list pre-exists
if(is_array($this->unreadThreadsList))
if(array_key_exists($thread['board'],$this->unreadThreadsList))
if(array_key_exists($thread['id'],$this->unreadThreadsList[$thread['board']]))
// Skip this result, already in
if($this->unreadThreadsList[$thread['board']][$thread['id']] == 1) continue;
$this->unreadThreadsList[$thread['board']][$thread['id']] = 1;
}
}
This assumes an array structure like:
array(
1 => array(
'board' => 1,
'id' => 2
),
2 => array(
'board' => 3,
'id' => 1
),
3 => array(
'board' => 7,
'id' => 2
));
for the result of "fetchThreadsSinceData($since)" and an array structure of
array(
1 => array(
2 => 1
),
2=> array(
2 => 1
),
3=> array(
2 => 1
));
for the $this->unreadThreadsList where the first index is the board and the second index is the thread id.
For the other functions why not simply unset them directly as well?
unset($this->unreadThreadsList[$boardid][$threadid]);
unset($this->unreadThreadsList[$boardid]);
Good luck!
Dennis M.