I have two classes. Database and Product. I successfully connected PHP with DB and I am able to print out data.
But I want to know if I am using class Product correctly? And if in future I add Product class method addProduct should I need to keep properties?
My Product class:
<?php
require_once 'DataBase.class.php';
class Product {
//Properties
// var $id;
// var $name;
// var $price;
//Methods
function __construct(){}
public function getAllProducts()
{
$db = Database::get();
$sql = "SELECT * FROM product";
$result = $db->select($sql);
return $result;
}
}
$product = new Product;
Right now it seems that I don't need properties.
I would separate the getAllProducts() function from the individual products class. Like this:
<?php
require_once 'DataBase.class.php';
function getAllProducts()
{
$db = Database::get();
$sql = "SELECT * FROM product";
$result = $db->select($sql);
return $result;
}
class Product {
// Properties:
public $sku;
public $name;
public $price;
public $size = '0';
public $weight = '0';
public $dimension = '0x0x0';
// Methods
function __construct($var1, $var2, $var3) // add or remove vars as needed
{
// use make a new product, example:
$this->sku = $var1;
$this->name = $var2;
$this->price = $var3;
// etc...
}
}
$product = new Product($var1, $var2, $var3);
// do stuff with the product
Your constructor should deal with instantiating product information for use with your database. Also, PHP is notoriously terrible for its character escape techniques. Prepared statements and typecasting will make your life easier in the long run.
Related
I'm trying to override my constructor to create an object based on a row in my database and I'm unsure of the best way to go about it. My goal is to be able to create the object given the constructor but also have the ability to create the object from a row in my database.
Here is the pseudocode for my given scenerio:
class PurchaseOrder
{
private $id;
private $title;
private $amount;
function __construct($title, $amount)
{
$this->title = $title;
$this->amount = $amount;
}
function constructFromDB($pdo, $id)
{
$poValues = queryPO($pdo, $id); // fetches from db (psuedocode);
$this->title = $poValues->title;
$this->amount = $poValues->amount;
}
}
// Create new purchase order
$po = new PurchaseOrder("Purchase Order 1", 100);
// Query purchase order from database
$queriedPO = new PurchaseOrder()->constructFromDB($conn, 1);
But as you know, I cannot leave the constructor empty for my object to be initialized. I cannot have it be a static function as I will need to be able to manipulate the object's properties.
The constructFromDB() method can be static and return an object:
public static function constructFromDB($pdo, $id)
{
$poValues = queryPO($pdo, $id); // fetches from db (psuedocode);
$title = $poValues->title;
$amount = $poValues->amount;
$class = __CLASS__;
return new $class($title, $amount);
}
Then call it statically:
$queriedPO = PurchaseOrder::constructFromDB($conn, 1);
im work with php and mysql, sometimes i need instantiate my php class in data access layer for return objects, load list etc... but sometimes I use the class constructor and others do not.
Can i create doble constructor in a class?
example:
class Student {
private $id;
private $name;
private $course;
function __construct() {
}
//get set id and name
function setCourse($course) {
$this->course = $course;
}
function getCourse() {
$this->course = $course;
}
}
class Course {
private $id;
private $description;
function __construct($id) {
this->id = $id;
}
//get set, id, description
}
In my access layer sometime I use the constructor in different ways
for example:
$result = $stmt->fetchAll();
$listStudent = new ArrayObject();
if($result != null) {
foreach($result as $row) {
$student = new Student();
$student->setId($row['id']);
$student->setName($row['name']);
$student->setCourse(new Course($row['idcourse'])); //this works
$listStudent ->append($sol);
}
}
But sometimes I need to use the constructor in another way, for example
$result = $stmt->fetchAll();
$listCourses = new ArrayObject();
if($result != null) {
foreach($result as $row) {
$course = new Course(); //but here not work, becouse Class course receives a id
$course->setId($row['idcourse']);
$course->setDescription($row['description']);
$listCourses->append($sol);
}
}
My english is very bad,
i hope you understand me
Use default arguments:
class Course {
private $id;
private $description;
function __construct($id = 0) {
this->id = $id;
}
// getters and setters for id and description
}
Now, you can use it like that:
$course = new Course(12); // works with argument
or:
$course = new Course(); // works without argument
$course->setId(12);
class Course {
private $id;
private $description;
public function __construct() {
// allocate your stuff
}
public static function constructWithID( $id ) {
$instance = new self();
//do your stuffs here
return $instance;
}
call like Course:: constructWithID(..id) when you have to pass id otherwise make object (new Course()).
I have a PHP class called Product:
class Product {
$id;
$name;
}
And another class that get data from database:
$stm = $this->dsn->prepare($sql);
$stm->execute();
$rst = $stm->fetchAll(PDO::FETCH_ASSOC);
How can I convert this PDO resultset ($rst) to an array of objects Product?
Use the PDO::FETCH_CLASS argument.
class Product {
public $id;
public $name;
}
$stm = $this->dsn->prepare($sql);
$stm->execute();
$result = $stm->fetchAll( PDO::FETCH_CLASS, "Product" );
http://php.net/manual/en/pdostatement.fetchall.php
Just change the way you're calling fetchAll()
$rst = $stm->fetchAll(PDO::FETCH_CLASS, 'Product');
My approach in this case would be to use a helper function within the Product class that builds a new instance of the object and returns it provided the inputs from the PDO.
Such as
public static function buildFromPDO($data) {
$product = new Product();
$product->id = $data["id"];
$product->name = $data["name"];
return $product;
}
Then inside of your PDO call, loop through the return and array_push onto an array containing all your products built via this function.
$products = array();
foreach ($rst as $r) {
array_push($products, Product::buildFromPDO($r));
}
You also might want to consider using an ORM if it seems like you'll be doing a ton of this kind of stuff.
You have to write a method to do it.
class Product {
$id;
$name;
public function loadData($data){
$this->id = $data['id'];
$this->name = $data['name'];
}
}
$Product = new Product();
$Product->loadData($database_results);
Or, if you're going to be doing this for every object, use a constructor..
class Product {
$id;
$name;
public function __construct($id, $pdo){
$pdo->prepare("select * from table where id = :id");
// do your query, then...
$this->id = $data['id'];
$this->name = $data['name'];
}
}
$Product = new Product($id, $pdo);
You can use constructor arguments (http://php.net/manual/en/pdostatement.fetchall.php)
$result = $stm->fetchAll( PDO::FETCH_CLASS, "Product", array('id','name'));
Note: properties must be public
here is my sample class to why i want to nest.
include("class.db.php");
class Cart {
function getProducts() {
//this is how i do it now.
//enter code here`but i dont want to redeclare for every method in this class.
//how can i declare it in one location to be able to use the same variable in every method?
$db = new mysqlDB;
$query = $db->query("select something from a table");
return $query
}
}
Take advantage of properties.
class Cart {
private $db;
public function __construct($db) {
$this->$db = $db;
}
public function getProducts() {
$query = $this->db->query( . . .);
return $query;
}
}
You'll create the database object outside of your class (loose coupling FTW).
$db = new MysqlDb(. . .);
$cart = new Cart($db);
Isolate the common code to each method/function into another private internal method/function.
If you need to have it run once automatically for the object when it's created, this is what __construct is for.
You could have something like this
<?php
class cart
{
protected $database;
function __construct()
{
$this->database = new mysqlDB;
}
function getProducts()
{
$this->database->query("SELECT * FROM...");
}
}
?>
__construct is the function that is called when you instantiate a class.
I am a learner, I have a class db to help me connect and fetch results in mySQL.
$set = $db->get_row("SELECT * FROM users");
echo $set->name;
this way i use echo results outside a class.
Now i have created another class name user and it has this function
public function name() {
global $db;
$set = $db->get_row("SELECT * FROM users");
$this->name = $set->name;
}
after initializing the class user, when i try to echo $user->name i dont get expected results.
Note i have declared above var $name; in class user
I'm pretty concerned by several things I see here
The method name name() is terribly uncommunicative as to what the method is supposed to do. Remember, methods are actions - try to give them some sort of verb in their name.
Usage of global in a class (or even usage of global period) when you should be using aggregation or composition.
You don't show any execution examples, but I can only assume you never actually call User::name(), which is why your test is failing
Here's some code that addresses these concerns.
<?php
class DB
{
/* Your methods and stuff here */
}
class User
{
protected $db;
protected $name;
public function __construct( DB $db )
{
$this->db = $db;
}
public function getName()
{
if ( is_null( $this->name ) )
{
$set = $this->db->get_row( "SELECT * FROM users" );
$this->name = $set->name;
}
return $this->name;
}
}
$db = new DB();
$user = new User( $db );
echo $user->getName();
class DB
{
public function get_row($q)
{
# do query and store in object
return $object;
}
}
class User
{
public $name;
public function __construct()
{
$this->name();
}
public function name() {
global $db;
$set = $db->get_row("SELECT * FROM users");
echo "<pre>".print_r($set)."</pre>"; # make sure $set is returning what you expected.
$this->name = $set->name;
}
}
$db = new DB();
$user = new User();
echo $user->name;
I am very much sorry, i figured out that problem was on my part, i was using cookies and had two cookies set which were giving problems :(