PHP Variable Variables - php

I am writing this comment class:
class Comment {
public $id;
public $post_id;
public $name;
public $email;
public $website;
public $body;
public $date;
public $ip_address;
public $status;
function __construct($id) {
global $db;
$resc = $db->query("SELECT * FROM blog_comments WHERE id='$id' LIMIT 1");
while($row = $db->fetch_assoc($resc)) {
while ($comment = current($row)) {
$key = key($row);
$this->$key = $comment{$key};
next($row);
}
}
}
}
Here is what the query inside the constructor will return when run in the database:
query results http://17webshop.com/wp-content/uploads/2009/10/Picture-2.png
But when I run it, this is what print_r(new Comment(1)); spits out:
Comment Object
(
[id] => 1
[post_id] => 1
[name] => J
[email] => j
[website] => h
[body] => b
[date] => 1
[ip_address] => :
[status] => 1
)
Any ideas why I'm only getting the first character of each field?
Thanks.

You want
$comment[$key]
$comment{$key} will give you the nth character of a string. Since $key itself is a string, PHP converts that to an integer 0 and you get the first char.

current/next is painful, and I'm not sure what's with the {} dereferencing.
Why not just:
$resc = $db->query("SELECT * FROM blog_comments WHERE id='$id' LIMIT 1");
while($row = $db->fetch_assoc($resc)) {
foreach($row as $key=>$value){
$this->$key = $value;
}
}

I think you need to change this line:
$this->$key = $comment{$key};
with:
$this->$key = $comment[$key];

Related

PDO::FETCH_CLASS Arguments

It's possible to create another instance to send as parameters on the current instance in PDO::fetchAll()?
if \PDO::FETCH_PROPS_LATE is set it will FIRSTLY call the __construct and SECONDLY set the properties. so the values you have passed to the __construct via the array will be overwritten.
But, when it overwritte the values, it doesn't understand the Voucher instance.
It is better illustrate
e.g.
<?php
class Voucher {
private $CD_ID, $CD_VOUCHER, $NR_EXPIRATION, $DT_VOUCHER, $IE_STATUS;
public function __construct($CD_ID, $CD_VOUCHER, $NR_EXPIRATION, $DT_VOUCHER, $IE_STATUS) {
$this->CD_ID = $CD_ID;
$this->CD_VOUCHER = $CD_VOUCHER;
$this->NR_EXPIRATION = $NR_EXPIRATION;
$this->DT_VOUCHER = $DT_VOUCHER;
$this->IE_STATUS = $IE_STATUS;
}
}
class Authentication {
private $CD_AUTH, $DT_AUTH, Voucher $CD_VOUCHER, $CD_IP, $CD_MAC, $CD_LOG;
public function __construct($CD_AUTH, $DT_AUTH, Voucher $CD_VOUCHER, $CD_IP, $CD_MAC, $CD_LOG) {
$this->CD_AUTH = $CD_AUTH;
$this->DT_AUTH = $DT_AUTH;
$this->CD_VOUCHER = $CD_VOUCHER;
$this->CD_IP = $CD_IP;
$this->CD_MAC = $CD_MAC;
$this->CD_LOG = $CD_LOG;
}
}
public function getAuthentications() {
try {
$sth = $this->db->prepare("SELECT `TB_AUTENTICACAO`.`CD_AUTH`, `TB_AUTENTICACAO`.`DT_AUTH`, `TB_VOUCHER`.`CD_ID`, `TB_VOUCHER`.`CD_VOUCHER`, `TB_VOUCHER`.`NR_EXPIRATION`, `TB_VOUCHER`.`DT_VOUCHER`, `TB_VOUCHER`.`IE_STATUS`, `TB_AUTENTICACAO`.`CD_IP`, `TB_AUTENTICACAO`.`CD_MAC`, `TB_AUTENTICACAO`.`CD_LOG` FROM `TB_AUTENTICACAO` INNER JOIN `TB_VOUCHER` ON `TB_VOUCHER`.`CD_ID` = `TB_AUTENTICACAO`.`CD_VOUCHER`;");
$sth->execute();
return $sth->fetchAll(\PDO::FETCH_CLASS | \PDO::FETCH_PROPS_LATE, "Models\\Authentication", array("TB_AUTENTICACAO.CD_AUTH", "TB_AUTENTICACAO.DT_AUTH", new \Models\Voucher("TB_VOUCHER.CD_ID", "TB_VOUCHER.CD_VOUCHER", "TB_VOUCHER.NR_EXPIRATION", "TB_VOUCHER.DT_VOUCHER", "TB_VOUCHER.IE_STATUS"), "TB_AUTENTICACAO.CD_IP", "TB_AUTENTICACAO.CD_MAC", "TB_AUTENTICACAO.CD_LOG"));
} catch (Exception $exc) {
die($exc->getMessage());
}
}
The result must be:
e.g.
Models\Authentication Object (
[CD_AUTH:Models\Authentication:private] => 2
[DT_AUTH:Models\Authentication:private] => 2016-03-22 10:44:00
[CD_VOUCHER:Models\Authentication:private] => Models\Voucher Object (
[CD_ID:Models\Voucher:private] => 1
[CD_VOUCHER:Models\Voucher:private] => xYgPB5
[NR_EXPIRATION:Models\Voucher:private] => 720
[DT_VOUCHER:Models\Voucher:private] => 2016-03-18 17:00:00
[IE_STATUS:Models\Voucher:private] => 0
)
[CD_IP:Models\Authentication:private] => 10.10.10.10
[CD_MAC:Models\Authentication:private] => abc
[CD_LOG:Models\Authentication:private] => 1
)
but I get:
e.g.
Models\Authentication Object (
[CD_AUTH:Models\Authentication:private] => 2
[DT_AUTH:Models\Authentication:private] => 2016-03-22 10:44:00
[CD_VOUCHER:Models\Authentication:private] => xYgPB5
[CD_IP:Models\Authentication:private] => 10.10.10.10
[CD_MAC:Models\Authentication:private] => abc
[CD_LOG:Models\Authentication:private] => 1
[CD_ID] => 1
[NR_EXPIRATION] => 720
[DT_VOUCHER] => 2016-03-18 17:00:00
[IE_STATUS] => 0
)
I would just keep it simple and define the variable as a class in the class itself. However, I am not sure why you have this issue, perhaps its because you're not attaching a variable to the new class?
If you're using a PHP 5.6+ you can make use of variable-length argument lists.
Seeing your code, I think it will boost read-ability by a-lot but the downside is that you need to make sure the correct number of variables are parsed into the constructor.
class Authentication {
private $CD_AUTH, $DT_AUTH, $CD_VOUCHER, $CD_IP, $CD_MAC, $CD_LOG;
public function __construct($CD_AUTH, $DT_AUTH, array $CD_VOUCHER, $CD_IP, $CD_MAC, $CD_LOG) {
...
$this->CD_VOUCHER = new \Models\Voucher(...$CD_VOUCHER);
...
# or go anonymous in php 7
$this->CD_VOUCHER = new class(...$CD_VOUCHER){
function __construct($CD_ID, $CD_VOUCHER, $NR_EXPIRATION, $DT_VOUCHER, $IE_STATUS){
...
}
}
}
}
public function getAuthentications() {
try {
$sth = $this->db->prepare("...");
$sth->execute();
return $sth->fetchAll(\PDO::FETCH_CLASS | \PDO::FETCH_PROPS_LATE, "Models\\Authentication", array("TB_AUTENTICACAO.CD_AUTH", "TB_AUTENTICACAO.DT_AUTH", ["TB_VOUCHER.CD_ID", "TB_VOUCHER.CD_VOUCHER", "TB_VOUCHER.NR_EXPIRATION", "TB_VOUCHER.DT_VOUCHER", "TB_VOUCHER.IE_STATUS"], "TB_AUTENTICACAO.CD_IP", "TB_AUTENTICACAO.CD_MAC", "TB_AUTENTICACAO.CD_LOG"));
} catch (Exception $exc) {
die($exc->getMessage());
}
}

Printing relations between members

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;
}
}

Accessing WP cron multidimensional array efficiently in PHP

I need to access multiple arrays, the problem lies when I get to the arrays I need like below, I can't access it traditionally because the key will be different every time.
I'm dealing with the following array:
Array
(
[oe_schedule_charge] => Array
(
[617cdb2797153d6fbb03536d429a525b] => Array
(
[schedule] =>
[args] => Array
(
[0] => Array
(
[id] => cus_2OPctP95LW8smv
[amount] => 12
)
)
)
)
)
There are going to be hundreds of these arrays and I need a way to efficiently access the data within them. I'm using the following code with expected output:
function printValuesByKey($array, $key) {
if (!is_array($array)) return;
if (isset($array[$key]))
echo $key .': '. $array[$key] .'<br>';
else
foreach ($array as $v)
printValuesByKey($v, $key);
}
$cron = _get_cron_array();
foreach( $cron as $time => $hook ) {
if (array_key_exists('oe_schedule_charge', $hook)) {
echo '<div>';
echo date('D F d Y', $time);
echo printValuesByKey($hook, 'amount');
echo printValuesByKey($hook, 'id');
echo '</div>';
}
}
But I've never had to deal with this much data, so I would like to take the proper precautions. Any light that can be shed on accessing a multidimensional array like this in an efficient way would be greatly appreciated.
I would consider loading it into an object, then writing member functions to get what you want.
class myclass {
private $_uniqueKey;
private $_schedule;
private $_args = array();
private $_amount = array();
private $_id = array();
public function __construct($arrayThing)
{
foreach($arrayThing['oe_schedule_charge'] as $uniqueKey => $dataArray)
{
$this->_uniqueKey = $uniqueKey;
$this->_schedule = $dataArray['schedule'];
$this->_args = $dataArray['args'];
}
$this->_afterConstruct();
}
private function _afterConstruct()
{
foreach($this->_args as $argItem)
{
if(isset($argItem['amount']) && isset($argItem['id']))
{
$this->_amount[] = $argItem['amount'];
$this->_id[] = $argItem['id'];
}
}
}
public function getUniqueKey()
{
return $this->_uniqueKey;
}
public function getSchedule()
{
return $this->_schedule;
}
public function getArgs()
{
return $this->_args;
}
public function printShitOut($time)
{
//You define this. But if you do a print_r( on the object, it will tell you all the items you need. )
}
//code would be like this:
$cron = _get_cron_array();
foreach( $cron as $time => $hook )
{
$obj = new myclass($hook);
$obj->printShitOut($time);
}

PHP object can not access variable

Using the following:
$last_book = tz_books::getLast($request->db, "WHERE book_id='{$request->book_id}'");
I get the following php object array,
[0] => tz_books Object
(
[db:tz_books:private] => com Object
[id] => 64BEC207-CA35-4BD2
[author_id] => 4F4755B4-0CE8-4251
[book_id] => 8FC22AA0-4A60-4BFC
[date_due] => variant Object
)
I then want to use the author_id, but for some reason it's not working.
Trying to use:
$tz_books->author_id;
Using print_r($last_book); prints the array to the console just fine. And Doing the following just to see if the correct variable was being used:
$author = $tz_books->author_id;
print_r($author);
Nothing is printed to the console, and even after digging through the php manual and trying a lot of alternatives, I can't seem to grab that variable. I'm hoping i'm making a rookie mistake and overlooking something stupid. Thank you for any help!
Edit: Class definition
private $db;
public $id;
public $author_id;
public $book_id;
public $date_due;
public function __construct($db, $values=null) {
$this->db = $db;
if ( $values != null ) {
foreach ( $values as $var => $value ) {
$this->$var = $value;
}
}
}
public static function retrieveAll($db, $where='', $order_by='') {
$result_list = array();
$query = 'SELECT '.
'id, '.
'author_id, '.
'book_id, '.
'date_due '.
"FROM tz_books $where $order_by";
$rs = $db->Execute($query);
while ( !$rs->EOF ) {
$result_list[] = new tz_books($db, array(
'id' => clean_id($rs->Fields['id']->Value),
'author_id' => clean_id($rs->Fields['author_id']->Value),
'book_id' => clean_id($rs->Fields['book_id']->Value),
'date_due' => $rs->Fields['date_due']->Value,
));
$rs->MoveNext();
}
$rs->Close();
return $result_list;
}
Your result object seems to be an array of books with 1 element.
Try
echo $tz_books[0]->author_id;
BTW, it also looks like you're escaping input by putting single quotes. This is not a reliable/recommended method. Use a database-specific escape function like this

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