I think this is a silly question - but I am not being able to fully grasp it :(
Suppose I have a class called Categories which has a function called getCategories()
class Categories
{
function __construct()
{
}
function getCategories()
{
//sql to get all categories from db
return $categories;
}
}
And in other classes I will do something like:
$cats = new Categories();
$cats->getCategories();
Now my question is, there are many places where I need to use the categories. So what if I created a variable called $cats as a member of categories class and loaded it in the constructor and just passed it back when anyone called getCategories() :
class Categories
{
var $cats;
function __construct()
{
$this->cats = $this->getCategories();
}
function getCategories()
{
//return loaded class variable instead of running db query again
return $this->cats;
}
}
This way I do not need to hit database every time anyone requests categories. Is this approach good? bad? Should I do this or stick with db query each time?
This way I do not need to hit database every time anyone requests categories. Is this approach good? bad? Should I do this or stick with db query each time?
This all really depends on the nature of your categories property. For example, could they change after you have pulled them down? If so then caching when you initially create the class and never hitting the database again could potentially mean working with stale data which may or may not be an issue for you.
On the other hand, if they are fairly static and very rarely change then caching them on first access might be a better alternative e.g.
function getCategories()
{
if (!isset($this->cats)) {
$this->cats = // load from DB
}
return $this->cats;
}
There is all good, but var is deprecated, you should use public, private or protected instead.
Related
I am wondering if such this subclassing structure is possible in PHP. If this is a duplicate I apologize as I couldn't figure out what this process would be called and the only I could find was a closed question with no answer.
I am working with multiple classes. For example we will say Main and User.
The Main class will hold all of the initiation code. So
class Main{
//Setters for core variables and data needed to make calls
...
protected function fetchInfo(){
//Do Stuff to return info from other source(Curl calls in my case)
}
}
and User
class User extends Main{
public function getName(){
$data = $this->fetchInfo();
return $data['name'];
}
}
But instead of having it where I would. Do $exampe1 = new Main(...); to set varaibles, and $example2 = new User(); to call the subclass to do $example2->getName(); is there a way to do something like $example = new Main(); whcih could then call the subclasses when needed like $example->User->getName();?
I know there are a lot of different ways this could be handled, but I want the classes separate for organization and I plan on having a lot of subclasses that need to pull info from that main class and would like to know if there is a way they can be linked in that fashion.
EDIT: The reason I dont want to just call User calls to get the function is I'll end up having 15+ classes that handle the returned data differently and making wonder if there was a better way than making a new Object for each one if I want to use it.
A "Main" is not a "User" so I would say this type of subclassing is a poor choice.
I might instead look at injection.
class MainDataHandler {
//...
}
class User {
private $main;
public function __construct(MainDataHandler $main) {
$this->main = $main;
}
public function getName() {
return $this->main->getData('name');
}
}
The benefits of injection is that your classes can work and be tested independently without dependencies on another class to do the work. Also if "Main" ever changes you your User class isn't dependent on how the new Main works.
Sorry if I am not using the best jargon, but I have run into an issue I want to solve early before I write too much code. Which of these options below is "better"? And is there a better way of doing this? Someone mentioned to me abstracting my code but another class seems to be the last thing I need. Also I feel like there's something I can do by potentially making my "get" function seen below into a public static function so that I can use it differently. (its not static right now)
Here is my situation:
I have 2 (relevant to this question) classes, DB (database) and Page (for getting my content to display on my website)
the DB class has a query method that prepares and execute my queries
the DB class also has methods for inserting, getting, deleting things from the database.
I now feel that I may not even need my page class because right on the webpage I can just use those DB methods to call my content. (I store all images, content, page title, description in mysql). Is this not a legitimate way to do this? Won't I need to create a new object each time? such as:
$pg_ID = 2;
$title = new DB($pgID);
$title->get('pages', $pgID, $lang); // 3 tables to pull from for each page
$images = new DB($pgID);
$images->get('images', $pgID, $lang);
$structure = new DB($pgID); // I need these tables mostly because my site is in two languages
$images->get('pages_list', $pgID);
I do not like this potential solution just because to me its counter intuitive. Why should I have to create new objects just to reuse a function? However, what I do right now is something I feel is going to get me some hate mail.
$page = new Page();
$page->find('pages', $pgID, $lang);
$page->lookup($pgID);
$page->retrieve('images', $pgID, $lang);
These are 3 separate functions in my Page class that perform very similar things. Find gets my pages content out of the database and returns it as an object. Lookup does basically the same thing but only needs to pass one variable because its only to do with the html structure of each page regardless of which language is being accessed. retrieve gets all images from a table that get shown in a slider with different language descriptions. But as you can see, all three functions do basically the same thing! They query the database. Thanks for the help with this I am literally just getting into this OOP and its driving me insane. Stack has been very helpful and I think I just didn't know how to search for this to find the answer. Feel free to point me to other questions/answers that I may have missed. It was hard for me to think of the keywords to search for.
we may create other classes indeed, but efficiently so. Maybe we can render DB a public state function. I like the idea of creating a database object, pass it as parameter to an other object, which could then format data with the link he just received:
$pg_ID = 2;
$db = new DB($pg_id);
$page = new Page($db,$pg_ID);
// make sure you assign the parameters a private properties in `Page()` ctor.
then, from inside your function, you can call images, titles and structures at will from $this
$title = $this->DB->get('pages', $this->pgID, $lang);
$images = $this->DB->get('images', $this->pgID, $lang);
$structure = $this->DB->get('pages_list', $this->pgID);
and you can those other method as well
$page->find('pages', $this->pgID, $lang);
$page->lookup($this->pgID);
$page->retrieve('images', $this->pgID, $lang);
Now we do not need to create a new object each time we want information from the database.
Now...
the way I access member functions here $this->pgID is better used by defining a getter: $this->pgID(). I like my getter to have the same name as the property. This might not be a very good idea though.
private function pgID() {
return $this->pgID;
}
As for abstract classes..
I did in fact come very lately into thinking abstract classes were quite cool indeed. I've some problem with wording it, having a constant constructor with custom mandatory functions and possible different implementation of classes seems awesome:
abstract class Page {
function __construct($db,$pgID,$lang,$params='') {
$this->db = $db;
$this->pgID = $pgID;
$this->lang = $lang;
$this->init($params);
}
function pgID() {
return $this->pgID;
}
function lang() {
return $this->lang;
}
abstract function init();
abstract function retrieve();
}
class Structure extends Page {
function init($params) {
// some specific to Structure foo here
}
function retrieve($what='pages_list') {
return $this->db->get($what,$this->pgID,$this->lang);
}
}
class Image extends Page {
function init($params) {
// some specific to Image foo here
}
function retrieve($what='images') {
$images = $this->db->get($what,$this->pgID,$this->lang);
// plus some foo to resize each images
return $images;
}
}
ok, hope you're still there! Now we have a Structure and Image class with requisites constructor arguments, generic functions and a custom retrieve function. We could use them that way:
$db = new DB(2);
$template = new Structure($db,2,'fr');
$template->retrieve();
$slideshow = new Image($db,4,'en');
$slideshow->retrieve();
I do hope you do not have to create a new instance of DB if you use a different page id :-)
jokes appart this helps me using classes in a better structured way, as I might have many different classes to represent different parts of a site, but when called from an index all of them will have the same function names, like retrieve() or print(), list()...
I don't want to get into the weeds on a SPECIFIC implementation for you situation, rather I am going to offer some generic guidance.
First off, you shouldn't have to create a separate database object (dbo) for title, images, or structure. Chances are the DSN used for each dbo you are initializing are the exact same, so I would create a singleton dbo which can be shared across multiple objects. For reference take a look at Doctrine's connection manager.
Secondly, I think your objectification could be implemented better. Following most ORMS implementation, you have a Record class and a Table class. The Record class is a specific instance of a Record in your schema, whereas the Table class executes queries against your store which may result in multiple records. These results are then hydrated into an array (of records).
So what I would suggest is something like this (code has not been tested and some of it has been stubbed for brevity):
class PageTable
{
public static function getById($id)
{
// Validate id, if invalid throw exception
$dbo = Database::getConnection();
$stmt = $dbo->prepare('SELECT * FROM page WHERE id = :id');
$stmt->bindParam(array('id' => $id));
$stmt->execute();
$result = $stmt->fetch();
$page = new Page;
// Hydration
$page->setId($result['id']);
$page->setImages($result['images']);
return $page;
}
}
class Page
{
protected $id;
protected $title;
public function setId($id){}
public function getId(){}
}
Hopefully this separation of Record and methods affecting a single, or multiple records makes sense. You should take a look at a DBAL, like Doctrine.
The other day, while developing my PHP project and implementing the User class, i started to wonder how this class should interact with the MySQL database the project is using.
Let me start with an example: let's say I have a getName() method, inside the User class, that returns the user's real name. What's the more fitting way to implement that method?
I came up with 2 solutions:
I put the DB query inside the getName() and only get what I need like this:
public function getName() {
// MySQL query code here
}
I create a load() method inside the User class that load all the user data inside the class structure and then the getName() is something like this:
private $name;
// Load all user data inside the class' structure
public function load() {
$this->name = // MySQL query here
}
public function getName() {
return $this->name;
}
I thought, not sure if mistakenly or not, that the first way is more efficient because i only get the data I need, while the second way is more OOP but less efficient.
So, here's the question: what is the better way? Why? Are there better ways?
Either way, consider storing/caching the results of that so you do not make a query every time you use getName on that object.
Also, consider not wrrying about all that by using a ORM/DBAL Solution like propel or doctrine.
Also check out Lazy Loading and the Active Record Pattern
Run your query just in time and only run it once (unless you know the value might change), try something like the following:
class User {
protected $data;
function getName()
{
if (!isset($data['name'])) {
// if you can load more than just $this->data['name'] in one query
// you probably should.
$this->data['name'] = // query here
}
return $this->data['name'];
}
}
Aside from the question being kinda broad (as there are countless patterns), the second way you mentioned is better IMO, and to add to it I would also suggest supplying ID as a parameter which you could then use to build a single query to fetch the user by ID and then manually assign all properties (from the fetched row).
Theoretical question on Laravel here.
So Example of the caching I'd do is:
Article::with('comments')->remember(5)->get();
Ideally I'd like to have an event for Article updates that when the ID of a instance of that model (that's already cached) is updated I want to forget that key (even if it's the whole result of the query that's forgotten instead of just that one model instance), it is possible to do so?
If not is there some way to implement this reasonably cleanly?
So i was looking for an answer to the same question as OP but was not really satisfied with the solutions. So i started playing around with this recently and going through the source code of the framework, I found out that the remember() method accepts second param called key and for some reason it has not been documented on their site (Or did i miss that?).
Now good thing about this is that, The database builder uses the same cache driver which is configured under app/config/cache.php Or should i say the same cache system that has been documented here - Cache. So if you pass min and key to remember(), you can use the same key to clear the cache using Cache::forget() method and in fact, you can pretty much use all the Cache methods listed on the official site, like Cache::get(), Cache::add(), Cache::put(), etc. But i don't recommend you to use those other methods unless you know what you're doing.
Here's an example for you and others to understand what i mean.
Article::with('comments')->remember(5, 'article_comments')->get();
Now the above query result will be cached and will be associated with the article_comments key which can then be used to clear it anytime (In my case, I do it when i update).
So now if i want to clear that cache regardless of how much time it remembers for. I can just do it by calling Cache::forget('article_comments'); and it should work just as expected.
Hope this helps everyone :)
I think a good way to do is like this:
$value = Cache::remember('users', $minutes, function()
{
return DB::table('users')->get();
});
and then use Model Observers to detect the event of updating the model
class UserObserver {
public function saving($model)
{
//
}
public function saved($model)
{
// forget from cache
Cache::forget('users');
}
}
User::observe(new UserObserver);
Currently there are no easy way. However I found this workaround, which so far worked for me.
First you have to extend Illuminate\Database\Query\Builder.
<?php
class ModifiedBuilder extends Illuminate\Database\Query\Builder {
protected $forgetRequested = false;
public function forget()
{
$this->forgetRequested = true;
}
public function getCached($columns = array('*'))
{
if (is_null($this->columns)) $this->columns = $columns;
list($key, $minutes) = $this->getCacheInfo();
// If the query is requested ot be cached, we will cache it using a unique key
// for this database connection and query statement, including the bindings
// that are used on this query, providing great convenience when caching.
$cache = $this->connection->getCacheManager();
$callback = $this->getCacheCallback($columns);
if($this->forgetRequested) {
$cache->forget($key);
$this->forgetRequested = false;
}
return $cache->remember($key, $minutes, $callback);
}
}
Then you have to create new class which extends Eloquent Model.
<?php
class BaseModel extends Eloquent {
protected function newBaseQueryBuilder() {
$conn = $this->getConnection();
$grammar = $conn->getQueryGrammar();
return new ModifiedBuilder($conn, $grammar, $conn->getPostProcessor());
}
}
Now when creating Eloquent Models, instead of extending Eloquent Models extend newly created BaseModel.
Now you can remember query result as usual.
YourModel::remember(10)->get();
When you want to discard the cached result all you have to do is
YourModel::forget()->get();
If you remember the result previously, after clearing the cached result, model will continue to remember the result for that amount of time.
Hope this helps.
I was testing for debug mode. So I found that if you put a test for app.debug in a constructor you are able to clear the cache associated with a key. Saves you having to duplicate the code for every function.
class Events {
public function __construct() {
if (\Config::get('app.debug')) {
Cache::forget('events');
}
}
public static function all() {
$events = \DB::table('events as e')
->select('e.*')
->where('enabled', 1)
->remember(30, 'events')
->get();
return $events;
}
}
I am trying to improve the method that I am using to to database transactions in a light framework I've built.
Information to understand the question:
Here's a class I've written (where connect.php loads up database credentials; a wrapper for the PHP PDO, stored in $db; and Base.php):
<?php
require_once('connect.php');
class Advertiser extends Base
{
public static function getByID($id)
{
global $db;
$sql = "SELECT * FROM advertiser WHERE advertiserid=?";
$values = array($id);
$res = $db->qwv($sql, $values);
return Advertiser::wrap($res);
}
public static function add($name)
{
$adv = new Advertiser(null, $name);
$res = $adv->save();
return $res;
}
public static function wrap($advs)
{
$advList = array();
foreach( $advs as $adv )
{
array_push($advList, new Advertiser($adv['advertiserid'], $adv['name']));
}
return Advertiser::sendback($advList);
}
private $advertiserid;
private $name;
public function __construct($advertiserid, $name)
{
$this->advertiserid = $advertiserid;
$this->name = $name;
}
public function __get($var)
{
return $this->$var;
}
public function save()
{
global $db;
if( !isset($this->advertiserid) )
{
$sql = "INSERT INTO advertisers (name) VALUES(?)";
$values = array($this->name);
$db->qwv($sql, $values);
if( $db->stat() )
{
$this->advertiserid = $db->last();
return $this;
}
else
{
return false;
}
}
else
{
$sql = "UPDATE advertisers SET name=? WHERE advertiserid=?";
$values = array ($this->name, $this->advertiserid);
$db->qwv($sql, $values);
return $db->stat();
}
}
}
?>
As you can see, it has fairly standard CRUD functions (Edit: Okay, so only CRU, in this implementation). Sometimes, I'll extend a class like this by adding more functions, which is what these classes are intended for. For example, I might add the following function to this class (assuming I add a column isBanned to the database):
public static function getBanned()
{
global $db;
$sql = "SELECT * FROM advertiser WHERE isBanned=1";
$res = $db->q($sql);
return Advertiser::wrap($res);
}
The question:
How can I create a catchall class that will also load up custom model classes when present and necessary?
For example, if I write the following code:
$model = new Catchall();
$banned = $model->Advertiser::getByID(4);
I would expect my catchall class to modify its queries so that all the references to the tables/columns are whatever name I chose (Advertiser, in this case), but in lower case.
In addition, if I wanted to create a custom function like the one I wrote above, I would expect my catchall class to determine that a file exists in its path (previously defined, of course) with the name that I've specified (Advertisers.php, in this case) and load it.
Advertisers.php would extends Catchall and would contain only my custom function.
In this way, I could have a single Catchall class that would work for all CRUD functions, and be able to easily expand arbitrary classes as necessary.
What are the ideas / concepts that I need to understand to do this?
Where can I find examples of this already in the wild, without digging through a lot of CodeIgniter or Zend sourcecode?
What is what I'm trying to do called?
General Stuff: I would look into Doctrine2 for examples of how they make an ORM in PHP. They use mapping in a markup language to say: this table has these columns of this type. Also, while not in PHP, the Django ORM is very easy to use and understand, and working through that tutorial for 20 minutes or so will really open your eyes to some neat possibilities. (it did for me)
A quick search for "php active record lightweight" returned several interesting examples that might start you down the right path.
PHP Ideas: I would look into the magic getter and setter in php, __GET and __SET that will let you set values on your objects without having to make a getter/setter for each field of each table. You could make a single __SET that will make sure that set field is a field in that table, and add it to the list of "fields to update" next time that object is saved. BUT, this is not really a good idea long term, as it gets out of hand quickly, and is brittle.
Advice: Lastly, I worked at a company that used a system that looks almost exactly like this, and I can say unequivocally, you do not want to try to scale this long term. A system like this (the active record pattern) can save massive amounts of time up front, by not having to write queries and things, but can cost tons down the road, if you ever want to start unit testing business logic on the object classes.
For example, it is not possible to mock/dependency inject that static GetById method (it is basically a global method), so every time that is called in code, the code will go to the real database and return a real object. It doesn't take much coding like this to make a system that is almost impossible to test, snarled and tightly coupled to the database.
While they can perform a little slower than your code above, if you are planning on having this around for a considerable amount of time, try looking into ORM tools.
Edit It's called Active Record.
There are a couple different design patterns for what you are trying to do. Look into Data Mapper and Active Record.
Using PHP's "magic method" __get, you can produce this functionality, when you access it via :
$model = new Catchall();
$banned = $model->Advertiser->getByID(4);
... it will a) check to see if the class Advertiser is already defined, b) check for a file called Advertiser.php and include it, or c) return a new instance of a generic class.
The syntax you used in your example with :: assumes that the returned class is static. I have not written this code to contend with that, but it should be trivial to do so.
See the docs: http://www.php.net/manual/en/language.oop5.overloading.php#language.oop5.overloading.methods
Quick and dirty example:
public function __get($name) {
$instance = false;
// see if there is already a class with the requested name
if (class_exists($name)) {
$instance = new $name();
}
// check to see if there is an object def for the requested object
if ($instance === false && file_exists(PATH_TO_OBJECTS.$name.'.php')) {
require_once(PATH_TO_OBJECTS.$name.'.php');
$instance = new $name();
}
// if instace is still not found, load up a generic
if ($instance === false)
$instance = new Catchall($name);
return $instance;
}