I've recently learnt OOP in Java and I'm trying to implement what I've learned in my PHP usersystem.
This is my current User class
class User {
public $id;
public $session;
public $email;
public $lastVisit;
public function __construct($id) {
$conn = new Conn();
$array = $conn->ExecuteCmdArray("SELECT * FROM user WHERE id = '".$id."'");
$this->session = $array['session'];
$this->email = $array['email'];
$this->id = $array['id'];
$this->lastVisit = $array['last_visit'];
}
}
^ Oh, and am I supposed to execute a SQL to retrieve the data?
However, after taking a look at some examples online, I looked at their User class, but realised that in it, only functions like login etc. are present. The attributes in the class are also only the username and password.
Shouldn't it contain all the other variables e.g gender, real_name as well? It seems to me that the user class does not store the userdata, but it's only used for logging in and stuff.
Is this how a User class in PHP usually works - which means my User class is done wrongly?
Well there is no right way to design a User class. It depends on the programmers likes, needs, skills and his understanding of OOP and Software-Design.
Seperation of Concerns
Oh, and am I supposed to execute a SQL to retrieve the data?
It's not recommended. Good software design is about creating decoupled self-contained components.
When designing Software it's a good practice to think out of the box and put yourself into another developers shoes. So if you had a User object without knowing what's going behind the scenes. Would you expect it to fire Database-Queries? No it's not a Users responsibility to query the database.
OOP is also about reusability. If we take your example: If I threw your User class into my own project. It would likely break. You are instantiating a Database Connection directly in the class. What if I had other ways of handling DB access? Everything would break.
Seperation of Concerns is the keyword here. And you should adhere to it whenever it's possible.
However, after taking a look at some examples online, I looked at their User class, but realised that in it, only functions like login etc. are present.
Ask yourself these questions:
Should a User know how to log in? How his sessions are managed or is this the task of another service maybe?
Would you expect that a User can log itself in if you didn't know the class?
You see. By just thinking about the concerns of a class you can eliminate problems in design before they even occur.
I would not expect my User that he knows how to log in. I rather would expect a service of my application which is explicitly dedicated to that task, to handle it.
<?php
$authentication = new UserAuthenticationService();
$authentication->attemptLogin('username', 'password');
if( $authentication->check() )
{
$user = $authentication->getUser();
echo $user->username();
}
Build your applications so that your classes are as self-contained as possible and only have the dependencies they really need. It's one of the keys of successful software-design.
It's all about your domain
The attributes in the class are also only the username and password.
Shouldn't it contain all the other variables e.g gender, real_name as well? It seems to me that the user class does not store the userdata, but it's only used for logging in and stuff.
That depends on your use case. If you're creating an application where users can anonymously post stories of their last hangover then why would you need a real name there?
If you however are creating some enterprise-business-app-thingy you probably want to store that data. What data your objects hold is defined by you, and only by you.
Let's take our hangover-site a step further. I want only minimal information from my users so it could look like this.
<?php
class User {
private $username;
private $email;
private $gender;
public function __construct( $username )
{
$this->username = $username;
}
public function username()
{
return $this->username;
}
//[...]
public function setUsername( $username )
{
$this->username = $username;
}
//[...]
}
I don't even store the password on my User class because I don't want to. I decide that I will have some kind of persistance manager and an authentication manager which handle those.
<?php
$authentication = new UserAuthenticationService();
$persistanceMapper = new UserPersistanceMapper();
$authentication->attemptLogin('username', 'password');
if( $authentication->check() )
{
// Let's rename the User just for fun
$user = $authentication->getUser();
$user ->setName('Thomas');
$persistanceMapper->persist( $user );
}
It really depends on your likes. But what I wanted to show in the first place is, that I have objects that do only the thing(s) that they are responsible for, or supposed to do
The User is able to alter it's own state and is able to provide me with it's data. But he does not know anything about the database.
UserPersistanceMapper knows how to persist a User (in a database or wherever it's supposed to)
UserAuthenticationService knows how a users session needs to be handled
I don't have the one object that handles all of it. Instead we have self-contained objects here that are together handling our stuff.
It all comes down to your likes
Is this how a User class in PHP usually works - which means my User class is done wrongly?
Eventually there is no right and no wrong. If you want to roll that way, do it! You may gain an initial time boost if you are not thinking about design. That may be okay for simple projects that are not hard to maintain.
At the time you are building larger applications however, it's always good to reflect on your own code.
Keep in mind:
Try to put yourself into some other developers shoes while designing your application
Visualize how objects are connected to each other before you start coding
Try to keep your classes as self-contained as possible (pass eventual dependencies from the outside)
Get stuff done! If you can't come up with a clean way to do something: Just make it work. Refactor things later. But make sure you have a periodic refactoring cycle. Don't put stuff aside and think "Yeah... whatever I'll do this later". You will end up with a lot of Code Smells this way.
Further reading
Seperation of Concerns
PHP: The Right Way
SOLID Principles
The drawback with the way you made your user class is when you manage lists of users, or process things about lots of users at a time you have to move around all this extra user data, whereas sometimes you would only need it's id, and email.
We can use two or more classes! In your exemple there would be a minimal User class, with very minimal attributes and functions, and a Full_User class, extending the first one.
class User {
public $id;
public $email;
public function __construct($array) {
$this->email = $array['email'];
$this->id = $array['id'];
}
}
class Full_User {
public $session;
public $lastVisit;
public function __construct($array) {
$this->session = $array['session'];
$this->lastVisit = $array['last_visit'];
parent::__construct($array);
}
}
I'd suggest passing the array of properties to the constructor instead of executing the statement. It will allow creating objects from some other data then a database.
$id = 12;
$conn = new Conn();
$minimal_array = $conn->ExecuteCmdArray("SELECT id,mail FROM user WHERE id = '".$id."'");
$full_array = $conn->ExecuteCmdArray("SELECT id,mail,session,lastVisit FROM user WHERE id = '".$id."'");
$user_for_listing = new User($minimal_array);
$full_user = new Full_User($full_array);
Related
I'd like to know if it is worthwhile to split a large class into different sections, and only use them when required. If so, what would be the best option?
I'm not sure about the resource impact of using a large class in a PHP file that makes very limited use of it when caching is enabled. Maybe this just isn't worth it, no matter how big the class is?
I had two models in mind... this one would need to be able to affect the "parent's" variables. I am fully aware that this code would not work, I just figured I'd type it in PHP+pseudo to explain it rather than pseudo-code alone.
class User {
public $id;
public $password;
public $password_hash;
public $post_count;
public function __construct($id) {
$this->id = $id;
}
}
subclass Password of User {
public function set($password) {
parent::$password = $password; }
public function generateHash() {
parent::$password_hash = hash("sha256", parent::$password, true); }
public function validate($password) {
return (hash("sha256", $password, true) === parent::$password_hash); }
}
subclass Post of User {
public function count() {
$db = ConnectionFactory::getFactory()->getConnection();
$sql = $db->prepare("SELECT 1 FROM `Forum_Posts` WHERE `User_ID`=:user");
$sql->execute(array('user' => parent::$id));
parent::$post_count = $sql->rowCount();
return parent::$post_count;
}
}
$some_bloke = new User(3);
$bob = new User(4);
$bob->Password->set('idonthaveaverygoodpassword');
$bob->Password->generateHash();
$lucy = new User(5);
echo $lucy->Post->count();
I also thought about using multiple traits, but it's not a pretty solution and I'm worried that it would increase memory usage pointlessly:
class User {
use BaseUser;
}
class User_Password {
use BaseUser;
use Password;
}
class User_Post {
use BaseUser;
use Post;
}
trait BaseUser {
public $id;
public $password;
public $password_hash;
public $post_count;
public function __construct($id) {
$this->id = $id;
}
}
trait Password {
//stuff
}
trait Post {
//stuff
}
$some_bloke = new User(3);
$bob = new User_Password(4);
$bob->setPassword('idonthaveaverygoodpassword');
$bob->generatePasswordHash();
$lucy = new User(5);
echo $lucy->countPosts();
I'm also very open to suggestions as to what to rename this post. I just wasn't quite sure.
A general framework, which could help with OOP independent of domain, is called SOLID. It can generically be applied to any domain by trying to comply with each principle it defines. That being said, SOLID is a just a framework, and code could fulfill solid principles while still bein difficult to work with :( I will try to answer with a pretty generic application of it to your domain:
Single Responsibility
Does each class only have a single reason to change. If the hashing algorithm or salt changed would that be isolated to a single spot? Yes. What if requirements changed and organization doesn't want to keep track of the raw password in memory? No. Both the User and the Password need to change.
Open/Closed
How would we create new types of Posts, Users, or passwords? What if the business would like to add an unauthenticated User, who wouldn't need a password. Could that be modeled in the system without modifying the User model? What if unauthenticated users always had 0 posts?
Liskov Substitution
This states, that all objects should be replaceable with instances of their subtypes. This is often only validated once the code that consumes your domain objects is created. In this case:
$some_bloke = new User(3);
$bob = new User(4);
$bob->Password->set('idonthaveaverygoodpassword');
$bob->Password->generateHash();
$lucy = new User(5);
echo $lucy->Post->count();
If $bob were an instance of a Post it would not be able to be instantiated using a Password which is a subclass of User, same goes for $lucy being an instance of a Password instead of a User.
Interface segregation
Dependency Inversion
In general I feel like Memory usage should be a non-issue for higher level (non-embedded) applications. Even for mobile, I find, abstractions and maintainability are more important than minimizing memory usage.
Additionally, inheritance based hierarchies can easily grow unwieldy and brittle. Composition (more like your second suggestion) may help to fulfill SOLID and minimize the brittleness. User could be provided a password strategy, which would define an interface for generating passwords, and allow password generation implementation to change, and leave user unaffected. Users that wanted to generate a password could delegate to their specific strategy.
When a user logs into my site, I create an instance of my User class, fetch some user-related data and store the object in the SESSION.
Some of the data I fetch from the database should be constant throughout the session AND I want the data to be accessible from other objects. I prefer using User::$static_value_in_class to $_SESSION['static_value_in_session'] when using the value from within another object, but I'm open to persuasion.
The problem is, the values aren't remembered when I serialize my User instance into the SESSION, then load a different page.
Class definitions:
class User {
public $name;
public static $allowed_actions;
public function __construct($username, $password) {
// Validate credentials, etc.
self::$allowed_actions = get_allowed_actions_for_this_user($this);
}
}
class Blog {
public static function write($text) {
if (in_array(USER_MAY_WRITE_BLOG, User::$allowed_actions)) {
// Write blog entry
}
}
}
login.php:
$user = new User($_POST['username'], $_POST['password']);
if (successful_login($user)) {
$_SESSION['user'] = $user;
header('Location: index.php');
}
index.php:
if (!isset($_SESSION['user'])) {
header('Location: login.php');
}
Blog::write("I'm in index.php! Hooray!")
// Won't work, because Blog requires User::$allowed_actions
Should I implement Serializable and write my own version of serialize() and unserialize() to include the static data?
Should I bite my lip and access the $_SESSION variable from within the Blog class?
Should I require a valid User instance sent to the Blog write() method?
Or maybe the internets has a better idea...
EDIT: Writing my real use case (not full code, but enough to get the gist).
My site handles groups of users with shared budget accounts.
Users may spend group money on certain things the group agreed upon, and they report transactions by creating instances of the Transaction class and sending it to the Bank class for database storage.
Bank class:
class Bank {
// Group-agreed reasons to spend money
public static $valid_transaction_reasons;
public function __construct(User $user) {
Bank::$valid_transaction_reasons = load_reasons_for_this_group($user->bank_id);
}
}
User class:
class User {
public $bank_id;
public function __construct($username, $password) {
$query = "SELECT bank_id FROM users WHERE username=$username AND password=$password";
$result = mysql_fetch_array(mysql_query($query));
$this->bank_id = $result['bank_id'];
}
}
Transaction class:
class Transaction {
public function __construct($reason, $amount) {
if (!in_array($reason, Bank::$valid_transaction_reasons)) {
// Error! Users can't spend money on this, the group doesn't cover it
}
else {
// Build a Transaction object
}
}
}
Actual code (login.php, or something):
$user = new User($_GET['uname'], $_GET['pword']);
$_SESSION['bank'] = new Bank($user);
// Some shit happens, user navigates to submit_transaction.php
$trans = new Transaction(REASON_BEER, 5.65);
// Error! Bank::$valid_transaction_reasons is empty!
As I mentioned in the comment, this is more a software design question than a question how to achieve this with PHP.
A static property is not part of the state of an object and will therefore not being serialized with it.
I'll give you a short example how I would solve a related problem. Imagine you have the following message class, that has a static $id property to make sure all instances have a unique id:
class Message {
public static $id;
public $instanceId;
public $text;
/**
*
*/
public function __construct($text) {
// the id will incremented in a static var
if(!self::$id) {
self::$id = 1;
} else {
self::$id++;
}
// make a copy at current state
$this->instanceId = self::$id;
$this->text = $text;
}
}
Serialization / Unserialization code:
$m1 = new Message('foo');
printf('created message id: %s text: %s%s',
$m1->instanceId, $m1->text, PHP_EOL);
$m2 = new Message('bar');
printf('created message id: %s text: %s%s',
$m2->instanceId, $m2->text, PHP_EOL);
$messages = array($m1, $m2);
$ser1 = serialize($m1);
$ser2 = serialize($m2);
$m1 = unserialize($ser1);
printf('unserialized message id: %s text: %s%s',
$m1->instanceId, $m1->text, PHP_EOL);
$m2 = unserialize($ser2);
printf('unserialized message id: %s text: %s%s',
$m2->instanceId, $m2->text, PHP_EOL);
To make sure that the id is unique across multiple script runs further work is nessary. You'll have to make sure that Message::$id is initialized before any object creation, using the value from last script run. This will get additionally wired when it comes to parallel PHP request on a webserver.
Its just an example with the simplest static property I know: an instance counter. In this case I would do so. But I hope you see that there is further work required to serialize / unserialize static properties without have side effects. And this depends on your application needs.
This question cannot be answered general I tend to say it makes no sense in any case to serialize static members. But I would appreciate comments on this.
Some of the data I fetch from the database should be constant throughout the session AND I want the data to be accessible from other objects.
If the data is really constant, then make them a constant.
If the data is not constant, consider whether they belong to the individual users (the object instances) or the User as the general concept (which is what a class is).
Should I implement Serializable and write my own version of serialize() and unserialize() to include the static data?
It does not make sense to store static members in the serialized object's string because they are independent from each other. Storing them would be a snapshot of the class state at the time the object was serialized.
Consider the following code snippet:
$user = new User;
$user::$allowed_actions = 'foo';
$string = serialize($user);
unset($user);
Now imagine some other part of your code does this:
echo User::$allowed_actions;
It still gives "foo" despite no object being in memory at the moment. That is because it's a static member. It's class state.
Now imagine you do this:
User::$allowed_actions = 'bar';
If you do unserialize the object now what should $allowed_actions be? Foo or Bar?
$user = unserialize($string);
echo $user::$allowed_actions;
The output should and would be "bar", because static members are about the class. The fact that we created, destroyed and brought back an object from it is irrelevant. It's all state of the class we changed here.
Also, take into account that statics are death to testability and you want to avoid them when possible. After all, it's called OOP not Class-Oriented-Progamming.
Should I bite my lip and access the $_SESSION variable from within the Blog class?
No, you should not access any of the superglobals anywhere but write abstractions for each of them or rather for the data inside them. They are merely input sources. In case of $_SESSION what you want to do is get all the data you need for that particular request right in your bootstrap and then pass the data around instead, e.g. recreate the user and pass that around.
Should I require a valid User instance sent to the Blog write() method?
In general, methods should be on the objects with the most information to fulfill an action. Whether that applies to your Blog::write I do not know. If the allowed_actions are part of the User instance, then probably yes, you should likely require a valid User instance.
Or maybe the internets has a better idea...
Another option would be to put the permissions into a dedicated Permissions object, holding the user role and it's permission. You could then lookup the permission from that list by passing in a User object. Search for Access Control Lists (ACL) for more info on possible implementations.
EDIT: Writing my real use case (not full code, but enough to get the gist).
If your concern is simply that Bank::$valid_transaction_reasons could be empty, then don't store Bank in the Session at all but only load it from the user when you run the transaction, e.g. create the Bank instance in submit_transaction.php (create it when you need it). That way you will never run into an error.
I know there are loads of questions on this, I have done quite a bit of reading. I'd like to ask this in context of my project to see what suggestions you may have.
I have quite a large web application with many classes, e.g. users and articles (which i consider to be the main classes) and smaller classes such as images and comments. Now on a page, lets say for example an article, it could contain many instances of images and comments. Makes sense right? Now on say an articles page I call a static method which returns an array of article objects.
That's the background, so here are the questions.
Since building a large amount of the app I came to realise it would be very useful to have a core system class containing settings and shared functions. There for I extended all of my classes with a new core class. Seemed relatively simple and quick to implement. I know CodeIgniter does something similar. I feel now though my app is becoming a bit messy.
Question Is this a good idea? Creating an instance of core is exactly what I want when calling an instance of an article, but what about when i'm creating multiple instances using the static method, or calling multiple images or comments on a page. I'm calling the core class unnecessarily right? Really it only needs to be called once per page (for example the constructor defines various settings from the database, I don't want to this every time, only once per page obviously), but all instances of all classes should have access to that core class. Sounds exactly like I want the singleton approach, but I know that's a waste of time in PHP.
Here's an idea of what my code looks like at this point. I've tried to keep it as simple as I can.
class core {
public function __construct(){
...define some settings which are retrieve from the database
}
public function usefulFunction(){
}
}
class user extends core {
public function __construct(){
parent::__construct();
}
public function getUser($user_id){
$db = new database();
$user = /* Get user in assoc array from db */
$this->__setAll($user);
}
public static function getUsers(){
$db = new database();
$users = /* Get users from database in assoc array from db */
foreach($users as $user) {
$arrUsers[] = new self();
$arrUsers[]->__setAll($user);
}
return $arrUsers;
}
private function __setAll($attributes) {
foreach($attributes as $key => $value)
{
$this->__set($key, $value);
}
}
public function __set($key, $value) {
$this->$key = $value;
}
}
The other issue I'm having is efficiently using/sharing a database connection. Currently each method in a class requiring a database connection creates a new instance of the database, so on a page I might be doing this 5 or 10 times. Something like the dependency injection principle sounds much better.
Question Now if i'm passing the instance of the DB into the new user class, i know I need something like this...
class user{
protected $db;
public function __construct($db){
$this->db = $db;
}
... etc
}
$db = new database();
$user = new user($db);
... but when I want to run the static function users::getUsers() what is the best way to gain access to the database instance? Do i need to pass it as a variable in each static method? (there are many static methods in many classes). It doesn't seem like the best way of doing it but maybe there isn't another way.
Question If extending all of my classes off the core class as suggested in part 1, can I create an instance of the DB there and access that some how?
Question I also have various files containing functions (not oop) which are like helper files. What's the best way for these to access the database? Again i've been creating a new instance in each function. I don't really want to pass the db as a parameter to each one. Should I use globals, turn these helper files into classes and use dependency injection or something different all together?
I know there is lots of advice out there, but most info and tutorials on PHP are out of date and don't ever seem to cover something this complex...if you can call it complex?
Any suggestions on how to best layout my class structure. I know this seems like a lot, but surely this is something most developers face everyday. If you need any more info just let me know and thanks for reading!
You asked in a comment that I should elaborate why it is a bad idea. I'd like to highlight the following to answer that:
Ask yourself if you really need it.
Do design decisions for a need, not just because you can do it. In your case ask yourself if you need a core class. As you already have been asked this in comments you wrote that you actually do not really need it so the answer is clear: It is bad to do so because it is not needed and for not needing something it introduces a lot of side-effects.
Because of these side-effects you don't want to do that. So from zero to hero, let's do the following evolution:
You have two parts of code / functionality. The one part that does change, and the other part that is some basic functionality (framework, library) that does not change. You now need to bring them both together. Let's simplify this even and reduce the frame to a single function:
function usefulFunction($with, $four, $useful, $parameters)
{
...
}
And let's reduce the second part of your application - the part that changes - to the single User class:
class User extends DatabaseObject
{
...
}
I already introduced one small but important change here: The User class does not extend from Core any longer but from DatabaseObject because if I read your code right it's functionality is to represents a row from a database table, probably namely the user table.
I made this change already because there is a very important rule. Whenver you name something in your code, for example a class, use a speaking, a good name. A name is to name something. The name Core says absolutely nothing other that you think it's important or general or basic or deep-inside, or that it's molten iron. No clue. So even if you are naming for design, choose a good name. I thought, DatabaseObject and that was only a very quick decision not knowing your code even, so I'm pretty sure you know the real name of that class and it's also your duty do give it the real name. It deserves one, be generous.
But let's leave this detail aside, as it's only a detail and not that much connected to your general problem you'd like to solve. Let's say the bad name is a symptom and not the cause. We play Dr. House now and catalog the symptoms but just to find the cause.
Symptoms found so far:
Superfluous code (writing a class even it's not needed)
Bad naming
May we diagnose: Disorientation? :)
So to escape from that, always do what is needed and choose simple tools to write your code. For example, the easiest way to provide the common functions (your framework) is as easy as making use of the include command:
include 'my-framework.php';
usefuleFunction('this', 'time', 'really', 'useful');
This very simple tow-line script demonstrates: One part in your application takes care of providing needed functions (also called loading), and the other part(s) are using those (that is just program code as we know it from day one, right?).
How does this map/scale to some more object oriented example where maybe the User object extends? Exactly the same:
include 'my-framework.php';
$user = $services->store->findUserByID($_GET['id']);
The difference here is just that inside my-framework.php more is loaded, so that the commonly changing parts can make use of the things that don't change. Which could be for example providing a global variable that represents a Service Locator (here $services) or providing auto-loading.
The more simple you will keep this, the better you will progress and then finally you will be faced with real decisions to be made. And with those decisions you will more directly see what makes a difference.
If you want some more discussion / guidance for the "database class" please consider to take a read of the very good chapter about the different ways how to handle these in the book Patterns of Enterprise Application Architecture which somewhat is a long title, but it has a chapter that very good discusses the topic and allows you to choose a fitting pattern on how to access your database quite easily. If you keep things easy from the beginning, you not only progress faster but you are also much easier able to change them later.
However if you start with some complex system with extending from base-classes (that might even do multiple things at once), things are not that easily change-able from the beginning which will make you stick to such a decision much longer as you want to then.
You can start with an abstract class that handles all of your Database queries, and then constructs them into objects. It'll be easy to set yourself up with parameterized queries this way, and it will standardize how you interact with your database. It'll also make adding new object models a piece of cake.
http://php.net/manual/en/language.oop5.abstract.php
abstract class DB
{
abstract protected function table();
abstract protected function fields();
abstract protected function keys();
public function find()
{
//maybe write yourself a parameterized method that all objects will use...
global $db; //this would be the database connection that you set up elsewhere.
//query, and then pack up as an object
}
public function save()
{
}
public function destroy()
{
}
}
class User extends DB
{
protected function table()
{
//table name
}
protected function fields()
{
//table fields here
}
protected function keys()
{
//table key(s) here
}
//reusable pattern for parameterized queries
public static function get_user( $id )
{
$factory = new User;
$params = array( '=' => array( 'id' => $id ) );
$query = $factory->find( $params );
//return the object
}
}
You'll want to do your database connection from a common configuration file, and just leave it as a global variable for this pattern.
Obviously this is just scratching the surface, but hopefully it gives you some ideas.
Summarize all answers:
Do not use single "God" class for core.
It's better to use list of classes that make their jobs. Create as many class as you need. Each class should be responsible for single job.
Do not use singletones, it's old technique, that is not flexible, use dependecy injection container (DIC) instead.
First, the the best thing to do would be to use Singleton Pattern to get database instance.
class Db{
protected $_db;
private function __construct() {
$this->_db = new Database();
}
public static function getInstance() {
if (!isset(self::$_db)) {
self::$_db = new self();
}
return self::$_db;
}
}
Now you can use it like db::getInstance(); anywhere.
Secondly, you are trying to invent bicycle called Active Record pattern, in function __setAll($attributes).
In third, why do you wrote this thing in class that extends Core?
public function __construct(){
parent::__construct();
}
Finally, class names should be capitalized.
I'm writing a user account system in PHP, with an emphasis on security, but I'm stuck on refactoring it into something cleaner and more usable.
The problem is trying to group the user account functionality together, but in separate classes. The way I'm doing it now is, there are a bunch of classes with public static methods that all take $username as the first parameter, and they use other static methods, passing the same $username as the first parameter as well. Obviously, OOP is a better way to go, especially since each method must strtolower the username in order to make DB queries, and must handle the case where the username provided doesn't exist at all.
The problem with putting everything in a "User" class is that it would be huge, and there would be a lot of completely unrelated code in the same file. For example, the Change Password code doesn't need to call methods related to validating the user's email or changing the user's (unrelated) settings.
I could have two classes: User and AuthenticatedUser, where AuthenticatedUser inherits User. User would implement all the functionality that is possible without the user being logged in, and AuthenticatedUser would be all the functionality that requires a login -- such as accessing the user's encrypted data. Maintenance code could use objects of User, and GUI code would get an AuthenticatedUser object after the user has logged in. But I don't want to cram all of the functionality into User.
Here's the list of some of operations that are related to a user account, just to show why they won't all fit in one class:
Login
Lockout user if >=X attempts in past Y minutes (includes methods for determining whether a user is locked out, adding a tick to the attempt count, etc).
Bypass the lockout with an email loop
Change password
Administrator change password (force)
Password reset (email loop) (incl. methods for initiating the reset, validating the email token, etc)
Set/get user data stored in plaintext
Set/get encrypted user data
Set/get account settings (password reset is allowed?, lock out the account on password failures?, is bypassing lockout with email loop allowed?, etc) Ideally these settings should be set/got near the code whose behavior depends on them.
Get the user's username in the proper case (as they specified it when creating account)
Email validation
A lot of functionality only used by specific code. E.g. get user "salt" used for key derivation.
A bunch more...
I was thinking I could do something like have a PasswordChanger class that inherits User, and implements the password changing functionality. So it would look like:
$proper = $user->getProperName();
...
$passChanger = $user->getPasswordChanger();
$result = $passChanger->changePassword($oldPass, $newPass);
...
$userLockout = $user->getUserLockout();
$result = $userLockout->isUserLockedOut();
...
$userEV = $user->getEmailValidation();
$result = $userEV->tryValidateEmail($token);
...
That's the best solution I've come up with so far. It lets me split up related functionality into it's own file, and saves from having to pass around the username. But it seems really weird -- I've never seen code like that before. It forces the superclass to know about all of its subclasses, which is bad design. Any ideas?
Edit: An alternative avoiding inheritance would be to have a PasswordChanger that has a a User. Like:
$passChanger = new PasswordChanger($user);
$passChanger->changePassword($old, $new); // uses $user->getUsername()
...
$emailValidator = new EmailValdiator($user);
$emailValidator->tryValidate($token);
"PasswordChanger has a User" vs. "PasswordChanger is a User." The former actually makes sense, so I like this way a little better.
Well, you've made a good start and you're asking the right questions. There is no single answer though. Design is an art rather than a science. It does sound like you are trying to re-design rather than refactor. You might find it easier if you start to refactor your code with only a loose idea of where your design might end up (a really good resource for refactoring is this book by Michael Feathers. As you refactor more and more you should find that a design emerges from the darkness! And often that design is not what you thought you'd end up with when you started out.
Oh, and btw inheritance is one of the most over-used aspects of OO. If you are thinking of inheritance, stop and think again. If you still think you need inheritance, stop and think some more. If you still think you need inheritance, it's possible that you do...
PasswordChanger and User have nothing in common so you should avoid to inherit them.
What I do in this case is something like:
class User {
var $pswChanger; //> -> Object of PasswordChanger
}
Basically put all the objects that you will need with User class within its attribute
You can of course access them with something like $this->pswChanger->method();
You might try using a decorator pattern. You can extend the UserDecorator by adding a validateDecorator, a notifyDecorator etc.
class User {
private $name;
private $password;
public function __construct($name, $pw) {
$this->name = $name ;
$this->password = $pw;
}
public function getUsername() {
return $this->name;
}
public function getPassword() {
return $this->password;
}
}
class UserDecorator {
protected $user;
protected $name;
protected $password;
public function __construct(User $user) {
$this->user= $user;
$this->setValues();
}
public function setValues() {
$this->name = $this->user->getUsername();
$this->password = $this->user->getPassword();
}
public function getUsername() {
return $this->name;
}
public function getPassword() {
return $this->password;
}
}
class PasswordChangeDecorator extends UserDecorator {
private $userdecorator;
public function __construct(UserDecorator $user) {
$this->userdecorator = $user;
}
public function changePassWord($newPw) {
$this->userdecorator->password = $newPw;
}
}
$user = new User("some random user name", "oldpw");
$userdecorator = new UserDecorator($user);
$pwdecorator = new PasswordChangeDecorator($userdecorator);
print $userdecorator->getPassword() . "\n";
// set the new password
$pwdecorator->changePassWord("newpw");
// test the outcome
print $userdecorator->getPassword();
I've just started using OOP PHP and ran into a question. I've set up a generic mysql class that allows me to connect to a database and has some functions to obtain records from a table:
class mysql{
//some lines to connect, followed by:
public function get_record($sql)
{
$result = mysql_result(mysql_query($sql));
return $result;
//obiously it's a bit more advanced, but you get the picture.
}
}
Next, I have a class to obtain user details:
class user{
__construct($id)
{
$this->id = $id
}
public function get_username($id)
{
$username = get_record("SELECT name FROM users WHERE id = '".$this->id."'");
return $username;
}
}
I tried this, but got the error that the function get_record was unkown. I solved this by adding $mysql = new mysql(); to the user class.
However, it feels quite inefficient to have to instantiate the mysql object for every class that uses my database methods (that's pretty much all of them).
Is there a way to make the mysql class and its methods accessible to all other classes, without having to call the mysql class in every method?
For one, you don't need to use singleton in this case - or actually, you almost never do. See this article, for example.
Second, I think your OO designs are a bit off. The main point of object-oriented programming and design is to isolate responsibility into separate classes. Right now, you're giving your User class two main responsibilities - store / carry one user's relevant data, and query the data service (in this case, a simple MySQL / database abstraction layer).
You should first move that functionality into a separate object. Usually, this is called a Service - so in this case, it's a UserService. A UserService has one responsibility: provide access to User objects. So it'd sorta look like this:
class UserService {
public function __construct($mysql); // uses the mysql object to access the db.
public function get($id) {
$result = $this->mysql->get_record("select x from y");
$user = new User($result['id'], $result['name']); // assuming user has a constructor that takes an id and a name
return $user;
}
public function save($user);
public function delete($user);
}
You tie it all together at the start of your request (or where you need to access users):
$mysql = new MySQL($credentials);
$service = new UserService($mysql);
$user = $service->find(1337);
It's not perfect, but it's a much neater design. Your MySQL object does what it needs to do (build a connection, execute queries), your user object is plain dumb, and your service does only one thing, i.e. provide a layer between the actual storage layer and the thing calling it.
Design your mysql class to be called statically:
$username = Mysql::get_record("SELECT name FROM users WHERE id = '".$this->id."'");
http://php.net/manual/en/language.oop5.static.php
This is a common problem, and so there is a common solution to this.
As you might know, in software development common solutions on common problems are called Design Patterns.
There are two design patterns that can help you solve this problem.
In a more abstract sense the problem you are facing is:
How can i make class A available in class B?
The Singleton pattern
"In the singleton pattern a class can distribute one instance of itself to other classes."
This is not exactly what you are looking for, as your website may use multiple database connections. However, it is used by a lot of people in this way.
Read some information about using a singleton class as a database provider here:
https://www.ibm.com/developerworks/library/os-php-designptrns/#N10124
More information on the singleton pattern in PHP:
http://www.fluffycat.com/PHP-Design-Patterns/Singleton/
Another sensible approach is the registry pattern:
Registry Pattern
You can find information about the registry pattern on the link below, as well as an implementation almost identical that you are looking for:
http://www.sitecrafting.com/blog/php-patterns-part/
Even more powerful is a combination between the singleton and the registry.
Good luck and enjoy learning OOP PHP!
You should pass in the mysql object to each user object. So it would look like this:
$mysql = new mysql();
$user = new user( $mysql, $id);
$name = $user->get_username();
class user {
public function __construct($mysql, $id) {
$this->mysql = $mysql;
$this->id = $id;
}
public function get_username() {
$username = $this->mysql->get_record("SELECT name FROM users WHERE id = '".$this->id."'");
return $username;
}
}
using global variables, although that is probably not the best option.
$mysql = new mysql();
function someFunction() {
global $mysql;
$mysql->get_record(...)
}
or a static method for your mysql class (see Singleton)
class mysql {
public static $theInstance = new mysql();
public static function getInstance() {
return $this->theInstance;
}
}
function someFunction() {
$database= mysql::getInstance();
$database->get_record(...)
}
Start to think to use Doctrine, it's better
http://www.doctrine-project.org/