I'm learning PHP and am trying to create some code outside of the tutorial I've been watching to understand it better and I can't seem to figure out where I'm going wrong with the code below. I have lots of other functions working just fine, just not this one. Can anyone point me in the right direction? Thanks.
The result I get is Catchable fatal error: Object of class User could not be converted to string on line 20, which is echo $user . "<br /><br />";
Here is my index.php
<?
$users = User::db_fields();
foreach($users as $user) {
echo $user . "<br /><br />";
}
?>
Here is my class User in user.php
<?php
class User extends OtherStuff {
public static function db_fields() {
global $db;
return static::find_by_sql("SHOW COLUMNS FROM my_table");
}
}
<?
Here is some of my OtherStuff class in other_stuff.php
class OtherStuff {
public static function find_by_sql($sql="") {
global $db;
$result_set = $db->query($sql);
$object_array = array();
while($row = $db->fetch_array($result_set)) {
$object_array[] = static::instantiate($row);
}
return $object_array;
}
public static function instantiate($record) {
$class_name = get_called_class();
$object = new $class_name;
foreach($record as $attribute => $value){
if($object->has_attribute($attribute)) {
$object->$attribute = $value;
}
}
return $object;
}
}
?>
Well....Your calling db_fileds() statically.
User::db_fields();
So it needs to be a static function..
public static function db_fields() {
EDIT
You could do this as a workaround...
Change your query
return static::find_by_sql("SELECT * FROM mytable LIMIT 1");
Then do this...
$fields = User::db_fields();
foreach($fields as $key=>$value ) {
echo $key; // This will give the field name
}
EDIT 2
To preserve the column names linked to the fields.
Although this is likely wrong, because now its instantiating multiple times, and what happens in a case where an object doesnt find an attribute and doesn't get written, then you miss a column.
But the idea is there...
while($row = $db->fetch_array($result_set)) {
foreach($row as $k=>$v){
$object_array[$k] = static::instantiate($row);
}
}
Well the array you're iterating over is $users, and the values you're getting from $users are going into $user.
But you're echoing $users (the Array). If the values in your $users array are all strings (or some other scalar value) you should be fine by changing your code to:
<?
$users = User::db_fields();
foreach($users as $user) {
echo $user . "<br /><br />";
}
?>
(I also added in your missing brace at the end)
You made a silly:
echo $users . "<br /><br />"; should have $user as the echo param
<?
$users = User::db_fields();
foreach($users as $user) {
echo $user . "<br /><br />";
?>
You were printing the original array every time
Edit:
The new error is a reflection of the fact that your User class does not explicitly define a way for objects of the class to be converted to strings. If you want to do a quick n dirty output, you can var_dump() your objects, but eventually you'll want to override the __toString() method. Check this out.
You can also simply make a function in the User class that returns the string you want and just call it with $user->StringifyUser(). The (main) difference between this approach is that PHP will not implicitly convert your User class objects to strings when used in your originally context.
Edit 2:
I would also check out the other answers, especially that of KyleK who addresses several key points that I did not touch on.
Related
I Have a Main class Employee which fetches Employees Details,Passed Inputs it fetches mysql results and RETURNS into a associate array into $row.
public function Result(){
$this->IsEmptyCheck();
$this->ConnectDb();
$this->QueryDb();
$this->RowCount();
$this->IfEmployeeFound();
}
public function IfEmployeeFound(){
if ($this->row_cnt > 0)
{
while ($row = $this->result->fetch_assoc()){
return($row);
}
}else{echo "No Results" ;}
}
public function CustomhtmlTabledisplay($row){
foreach ( $row as $key => $value ) {
echo .....
echo "<td>".$value['employee_name']."</td>\n";
echo "<td>".$value['age']."</td>\n";
echo "<td>".$value['familydetails']."</td>\n";
echo .....
}
}
I am running the below php call calling the employee class and executing above functions in it like this.
$check = new Employee($employeeid);
$check->Result()->CustomhtmlTabledisplay();
$check->CloseDb();
How can i achieve it ?
I would like to fetch the data by passing the mysql returned rows array from
IfEmployeeFound() into CustomhtmlTabledisplay();
I would like to display employee details by executing this type of query
$check->Result()->CustomhtmlTabledisplay();
(If I understood). For doing next - by executing this type of query:
$check->Result()->CustomhtmlTabledisplay();
You need return $this in end of every method for chaining methods. And store need data in property-fields of your Main Class.
EDIT
If you want use your class like this
$check->CustomhtmlTabledisplay(($check->Result());
change class methods to:
public function Result(){
$this->IsEmptyCheck();
$this->ConnectDb();
$this->QueryDb();
$this->RowCount();
return $this->IfEmployeeFound();
}
public function IfEmployeeFound(){
$out = array();
if ($this->row_cnt > 0){
while ($row = $this->result->fetch_assoc())
$out[] = $row;
}
return empty($out)? null: $out;
}
public function CustomhtmlTabledisplay($rows){
if($rows){
foreach ( $rows as $row) {
echo .....
echo "<td>".$row['employee_name']."</td>\n";
echo "<td>".$row['age']."</td>\n";
echo "<td>".$row['familydetails']."</td>\n";
echo .....
}
}
}
You can use
require_once (employee.php); //employee is the file where you have the methods
And instance the class employee
I can't make a simple echo.
I have an admin.class.php
public static function get_quota() {
return self::find_by_sql("SELECT * FROM quota");
}
public static function find_by_sql($sql="") {
global $database;
$result_set = $database->query($sql);
$object_array = array();
while ($row = $database->fetch_array($result_set)) {
$object_array[] = self::instantiate($row);
}
return $object_array;
}
And my echo code in index.php
<?php
$admin = User::find_by_id($_SESSION['user_id']);
$admin_class = new Admin();
$get_quota = Admin::get_quota();
$sql = "SELECT * FROM quota";
$get_quota = Admin::find_by_sql($sql);
?>
.
.
.
<?php echo $get_quota->daily_a; ?>
So my problem is, that the code is not working. I cannot echo my data. Can you help me, please?
You have a couple of problems here:
<?php echo $get_quota->daily_a; ?>
This line references the $get_quota variable and searches for a member field daily_a. Try this:
<?php echo "Quota is:".var_export($get_quota->daily_a,true); ?>
This will show that that is simply an empty variable.
However, also note:
$get_quota = Admin::get_quota();
$sql = "SELECT * FROM quota";
$get_quota = Admin::find_by_sql($sql);
Here you are calling two separate methods from Admin and setting the variable $get_quota to the result. The second overwrites the first. Therefore the get_quota() method doesn't help us here: we need to know what your find_by_sql() method returns.
EDIT (Post new code added to question)
You can implement logging/echoing within the function you've a problem with:
public static function find_by_sql($sql="") {
global $database; //Note this is bad practice (1).
$result_set = $database->query($sql);
echo "Result Set: ".var_export($result_set,true)."\n";//This should return something if you're getting something back from the database. Also, remove this for runtime (obviously).
if (count($result_set) <= 0) { //constraint checking is always good! And cheap!
error_log("An unexpected number of rows (0) was received from the database for query='".$sql."'.");
}
$object_array = array();
while ($row = $database->fetch_array($result_set)) {
$object_array[] = self::instantiate($row); //Ensure that the instantiate function returns something!
}
echo "Object Array: ".var_export($object_array, true)."\n";//double-check your instantiate function is working
return $object_array;
}
Based on this code, your problem is likely with the instantiate function; if it's not returning anything, $object_array is probably empty. (But not null!).
(1) You should avoid grabbing global variables like this. Instead, instantiate a class that holds and manages your database connection. Then make your find_by_sql function non-static and have a member field pointing to your database.
This is not really a problem but more of a question.
My question is how it's 'supposed to be' programmed.
It might not be too clear to explain, though.
So my question is; do I have to make multiple methods to retrieve data from a database?
For example, I have a table called FRUITS.
It contains the ID, name and date the fruit was added.
Now I want to get the name of the fruit based on a given ID, and later on in the script I want to get the date of the fruit as well.
Should I make one method such as get_fruit($id) which returns both the name and date, or two separate methods get_name($id) and get_date($id)?
Thanks in advance.
You should use one object which would contain all the required data. For example:
class Fruit {
protected ... variables;
public function getId() {...}
public function getDate() {...}
...
}
Also implementing __set and __get would be nice example of using full php potential.
You also may implement save() method (or extend database row class, such as Zend_Db_Table_Row.
So whole code would look like:
$fruit = $model->getFruid( 7); // $id = 7 :)
echo $fruit->id; // would call internally $fruit->__get( 'id')
echo $fruit->date;
// And modification:
$fruit->data = '2011-08-07';
$fruit->save();
EDIT: using separate methods to load certain data is useful (only?) when you need to load large amount of data (such as long texts) which is required only on one place in your code and would affect performance.
EDIT 2: (answer to comment):
__get and __set are called when you try to access undefined property of an object, for example:
class Foo {
public $bar;
public function __get( $name){
echo $name "\n";
return 'This value was loaded';
}
}
// Try to use
Foo $foo;
echo $foo->bar . "\n";
echo $foo->foo . "\n";
There are two "large" approaches to this that I know about:
// First use __get and __set to access internal array containing data
class DbObject {
protected $data = array();
public function __get( $propertyName){
// Cannot use isset because of null values
if( !array_key_exits( $propertyName,$this->data)){
throw new Exception( 'Undefined key....');
}
return $this->data[ $propertyName];
}
// Don't forget to implement __set, __isset
}
// Second try to call getters and setter, such as:
class DbObject {
public function getId() {
return $this->id;
}
public function __get( $propertyName){
$methodName = 'get' . ucfirst( $propertyName);
if( !method_exits( array( $this, $methodName)){
throw new Exception( 'Undefined key....');
}
return $this->$methodName();
}
}
To sum up... First approach is easy to implement, is fully automatized... You don't need large amount of code and sources would be pretty much the same for every class. The second approach required more coding, but gives you a better control. For example:
public function setDate( $date){
$this->date = date( 'Y-m-d h:i:s', strtotime( $date));
}
But on the other hand, you can do this with first approach:
class Fruit extends DbObject {
public function __set( $key, $val){
switch( $key){
case 'date':
return $this->setDate( $val);
default:
return parent::__set( $key, $val);
}
}
}
Or you can use total combination and check for getter/setter first and than try to access property directly...
here is the code how you can use the one function to get different field's value.
function get_fruit($id,$field = ''){
$sql = "select * from table_name where id = $id";
$result = mysql_fetch_object(mysql_query($sql));
if($field != ''){
return $result->$field;
}else{
return $result;
}
}
echo get_fruit(1,'field_name');
class data_retrieve
{
public $tablename;
public $dbname;
public $fieldset;
public $data_array;
public $num_rows
function __construct()
{
$this->tablename='junk';
$this->dbname='test';
$this->fieldset=array('junk_id');
}
function getData($where_str)
{
$this->data_array= array();
global $dbconnect, $query;
if($dbconnect ==0 )
{
echo" Already Connected \n ";
$dbconnect=db_connect("objectdb") or die("cannot connect");
}
$where_str;
if(empty($where_str))
{
$where_str=NULL;
}
else
{
$where_str= "where". $where_str ;
}
$query= "select * from $this->tablename $where_str";
$record= mysql_query($query) or die($query);
$recNo=mysql_num_rows($record);
$this->num_rows=$recNo;
while($row= mysql_fetch_assoc($record))
{
$this->data_array[]=$row;
}
mysql_free_result($record);
return $this->data_array;
}
class fruit extends data_retrieve
{
function __construct()
{
parent::__construct();
$this->tablename='fruit';
$this->fieldset=array('fruit_id','fruit_name','date');
}
}
then
in your file create a fruit object like
$str="fruit_id=5";
$fruit_data = new fruit();
$records=$fruit_data->getData($str);
to display
foreach($records as $row )
{
print <<< HERE
<label class='table_content' > $row[fruit_id]</label>
<label class='table_content' > $row[fruit_name]</label>
<label class='table_content' > $row[date]</label>
HERE;
}
I'm working on a class that will count twitter reactions to a link and also display them.
Currently I'm working on the counting portion and my count always equals 0 even though the array created in the constructor has multiple elements.
Any help would be appreciated. Thanks.
<?php
class TwitterReactions{
function __construct($url){
if($url){
$output=array();
$query = 'http://search.twitter.com/search.json?q='.$url;
$reactions=file_get_contents($query);
$reactions_array=json_decode($reactions, TRUE);
foreach($reactions_array as $results){
foreach($results as $result){
$output['user'][]=$result['from_user'];
$output['image'][]=$result['profile_image_url'];
$output['message'][]=$result['text'];
$output['date'][]=$result['created_at'];
}
}
return $output['user'];
} else {
echo "<p>Please provide a url...</p>";
}
}
function count_reactions($output){
//print_r($output);
$count = count($output['user']);
return $count;
}
}
?>
I agree with some of what Aliaksandr Astashenkau has in his answer but there are still some problems with the class.
It looks to me as if your initial problem was that you were expecting the __construct to return $output and you were then passing the object that you created into the count_reactions() method. Something like this...
$twitter = new TwitterReactions($url);
$count = $twitter->count_reactions($twitter);
You don't have your call to the count_reactions() method posted so this is just a hunch. If that's how you were using it the constructor it isn't meant to be used that way. Constructors always return a new instance of the class. You cannot return any other type of value from a constructor. You cannot use the return keyword in the __construct method.
As Aliaksandr Astashenkau points out $output should be a class member. I would also make $count a class member. In this case there's not much of a point of making either private so you don't really need accessor methods either but you can include them if you want.
I would make the class something like this...
<?php
class TwitterReactions
{
public $url = '';
public $output = array();
public $count = 0;
function __construct($url)
{
$this->url = $url;
$query = 'http://search.twitter.com/search.json?q='.$url;
$reactions=file_get_contents($query);
$reactions_array=json_decode($reactions, TRUE);
foreach($reactions_array as $results)
{
foreach($results as $key => $result)
{
// I find it easier if the data is arranged by each tweet but you can keep the array structure how you have it.
$this->output[$key]['user'] = $result['from_user'];
$this->output[$key]['image'] = $result['profile_image_url'];
$this->output[$key]['message'] = $result['text'];
$this->output[$key]['date'] = $result['created_at'];
}
}
$this->count = count($this->output);
}
}
You could then use the class like this
$twitter = new TwitterReactions($url);
// you now have access to output directly
$twitter->output;
// and count
$twitter->count;
Anyhow there are many ways to accomplish the same thing but I hop this helps give you some ideas.
You probably want to make an $output array to be a property of your class. Then $this->output would be availbale in count_reactions method.
<?php
class TwitterReactions {
public $output;
function __construct($url){
if($url){
$output=array();
$query = 'http://search.twitter.com/search.json?q='.$url;
$reactions=file_get_contents($query);
$reactions_array=json_decode($reactions, TRUE);
foreach($reactions_array as $results){
foreach($results as $result){
$output['user'][]=$result['from_user'];
$output['image'][]=$result['profile_image_url'];
$output['message'][]=$result['text'];
$output['date'][]=$result['created_at'];
}
}
$this->output = $output;
return $output['user'];
} else {
echo "<p>Please provide a url...</p>";
}
}
function count_reactions($output){
//print_r($this->output);
$count = count($this->output['user']);
return $count;
}
}
I've never tried OO PHP before so I decided to make a simple CMS to learn more. I am having a problem loading values into a multi-dimensional array.
class Article {
private $index = 0;
private $article;
public function Article() {
$get_articles = mysql_query("SELECT * FROM `articles`");
while ($result = mysql_fetch_array($get_articles)) {
echo $result["article"];
$this->article[$index]["Tags"] = $result["tags"];
$this->article[$index]["Categories"] = $result["categories"];
$this->article[$index]["Date"] = $result["date"];
$this->article[$index]["Article"] = $result["article"];
$this->article[$index]["URL"] = $result["url"];
$index++;
}
}
public function getArticle($articleID) {
return $this->article[$articleID]["Article"];
}
public function getTags($articleNumber) {
}
public function getCategories($articleNumber) {
}
public function getDate($articleNumber) {
}
}
The line echo $result["article"] outputs the one and only article value just fine, but apparently doesn't put it into the array?
$art = new Article();
echo $art->getArticle(0);
This doesn't output the article however. Would someone so kindly point out my noob mistake?
You didn't initialize your array.
$this->article = array();
while ($result = mysql_fetch_array($get_articles)) {
$this->article[$index] = array();
You probably should define your $index variable before using it in the loop. Maybe set it to the primary key field you retrieved from your query.
<?php
$index = $result['id'];
$this->article[$index]['tags'] = ...
You also need to initialize the $article member variable.
<?php
class Article {
private $article = array();
Remember that you define member variables within a class to be referenced via $this-> so you also don't need to define private $index = 0; in your class definition. Just define it inside the method.
You'll notice you used $this->article but not $this->index if you want to keep track of the length for the life of the object you'll need to replace $index with $this->index