Overview
We are learning PHP OOP and decided to create a simple app with 3 database tables, one a basic users table, the other two containing information about the users' favorite food and favorite restaurant.
To help help others learn this and other best practices a bit easier, we welcome PRs, issues, and other contributions to our GitHub repository.
Goal/Output
Our current goal is to create two pages:
Page 1 output:
"Welcome to the app, Jenn"
<?php
namespace PHPBestPractices1OOP\Controller;
use PHPBestPractices1OOP\Request\Request;
use PHPBestPractices1OOP\Response\Response;
use PHPBestPractices1OOP\Domain\User\UserFactory;
class GreetSingleUserPage
{
/**
* @var Response
*/
private $response;
/**
* @var Request
*/
private $request;
/**
* @var UserFactory
*/
private $userFactory;
/**
* GreetSingleUserPage constructor.
* @param Request $request
* @param Response $response
* @param UserFactory $userFactory
*/
public function __construct(
Request $request,
Response $response,
UserFactory $userFactory
) {
$this->response = $response;
$this->request = $request;
$this->userFactory = $userFactory;
}
public function __invoke()
{
// create user object
$userObject = $this->userFactory->createUser(2);
// this will display greeting message to the user
$this->response->setView("greetSingleUser/index.php");
$this->response->setVars(
array(
"name" => $userObject->getName()
)
);
return $this->response;
}
}
Page 2 output:
"My name is Jenn, age is 28, favorite restaurant is KFC and favorite food is Fried Chicken"
<?php
namespace PHPBestPractices1OOP\Controller;
use PHPBestPractices1OOP\Request\Request;
use PHPBestPractices1OOP\Response\Response;
use PHPBestPractices1OOP\Domain\User\UserFactory;
class DisplayUserInformationPage
{
/**
* @var Response
*/
private $response;
/**
* @var Request
*/
private $request;
/**
* @var UserFactory
*/
private $userFactory;
/**
* DisplayUserInformationPage constructor.
* @param Request $request
* @param Response $response
* @param UserFactory $userFactory
*/
public function __construct(
Request $request,
Response $response,
UserFactory $userFactory
) {
$this->response = $response;
$this->request = $request;
$this->userFactory = $userFactory;
}
public function __invoke()
{
// create user object
$userObject = $this->userFactory->createUser(2);
// this will display the user's information
$this->response->setView("displayUserInformation/index.php");
$this->response->setVars(
array(
"name" => $userObject->getName(),
"age" => $userObject->getAge(),
"restaurant" => $userObject->getFavoriteRestaurantName(),
"food" => $userObject->getFavoriteFoodName()
)
);
return $this->response;
}
}
Database
In practice these are sql databases, note though if you happen to look at our github we've "faked" this db using PHP arrays to make the project easier to run and try out
users
id name age favoriteRestaurantId favoriteFoodId
1 Mike 30 1 1
2 Jenn 28 3 3
restaurants
id name averagePrice style
1 McDonalds 1 American
2 Taco Bell 1 Mexican
3 KFC 2 American
foods
id name caloriesPerOunce
1 French Fries 100
2 Hamburger 135
3 Fried Chicken 97
User class
Here is our User.php. We also have Restaurant and Food classes.
<?php
namespace PHPBestPractices1OOP\Domain\User;
use PHPBestPractices1OOP\Domain\Food\Food;
use PHPBestPractices1OOP\Domain\Restaurant\Restaurant;
class User
{
// region vars
/**
* @var int
*/
private $userId;
/**
* @var string
*/
private $name;
/**
* @var int
*/
private $age;
/**
* @var Restaurant
*/
private $favoriteRestaurant;
/**
* @var Food
*/
private $favoriteFood;
// endregion
// region set
/**
* @param $userId
*/
public function setId($userId)
{
$this->userId = $userId;
}
/**
* @param string $name
*/
public function setName($name)
{
$this->name = $name;
}
/**
* @param int $age
*/
public function setAge($age)
{
$this->age = $age;
}
/**
* @param $favoriteRestaurant
*/
public function setFavoriteRestaurant(Restaurant $favoriteRestaurant)
{
$this->favoriteRestaurant = $favoriteRestaurant;
}
/**
* @param $favoriteFood
*/
public function setFavoriteFood(Food $favoriteFood)
{
$this->favoriteFood = $favoriteFood;
}
// endregion
// region get
public function getId()
{
return $this->userId;
}
/**
* @return string
*/
public function getName()
{
return $this->name;
}
/**
* @return int
*/
public function getAge()
{
return $this->age;
}
/**
* @return Restaurant
*/
public function getFavoriteRestaurant()
{
return $this->favoriteRestaurant;
}
/**
* @return string
*/
public function getFavoriteRestaurantName()
{
return $this->favoriteRestaurant->getName();
}
/**
* @return string
*/
public function getFavoriteFoodName()
{
return $this->favoriteFood->getName();
}
/**
* @return Food
*/
public function getFavoriteFood()
{
return $this->favoriteFood;
}
// endregion
}
UserFactory
<?php
namespace PHPBestPractices1OOP\Domain\User;
use PHPBestPractices1OOP\Domain\UsersTransactions\UsersTransactions;
use PHPBestPractices1OOP\Domain\Restaurant\RestaurantFactory;
use PHPBestPractices1OOP\Domain\Food\FoodFactory;
class UserFactory
{
/**
* @var UsersTransactions
*/
private $usersTransactions;
/**
* @var FoodFactory
*/
private $foodFactory;
/**
* @var RestaurantFactory
*/
private $restaurantFactory;
/**
* UserFactory constructor.
* @param UsersTransactions $usersTransactions
* @param FoodFactory $foodFactory
* @param RestaurantFactory $restaurantFactory
*/
public function __construct(
UsersTransactions $usersTransactions,
FoodFactory $foodFactory,
RestaurantFactory $restaurantFactory
) {
$this->usersTransactions = $usersTransactions;
$this->foodFactory = $foodFactory;
$this->restaurantFactory = $restaurantFactory;
}
/**
* create an instance of User class
*
* @param int $userId
* @return User
*/
public function createUser($userId)
{
$userObject = new User();
// get user data from the db and set to User object
$userRow = $this->usersTransactions->getUserById($userId);
$userObject->setName($userRow["userRow"]["name"]);
$userObject->setAge($userRow["userRow"]["age"]);
// create restaurant object and set user's favorite restaurant
$restaurantObject = $this->restaurantFactory->createResturant($userRow["userRow"]["favoriteRestaurantId"]);
$userObject->setFavoriteRestaurant($restaurantObject);
// create food object and set user's favorite food
$foodObject = $this->foodFactory->createFood($userRow["userRow"]["favoriteFoodId"]);
$userObject->setFavoriteFood($foodObject);
return $userObject;
}
/**
* create collection of User class instances for user's ids
*
* @param array $userIdsArray
* @return array
*/
public function createUsersCollection($userIdsArray)
{
// users collection
$usersCollection = array();
// loop through users array
foreach ($userIdsArray as $userId) {
$usersCollection[] = $this->createUser($userId);
}
return $usersCollection;
}
}
Our Question
Our current User
class works fine, but is slower than it could be for Page 1. Page 1 only requires the user's name, Jenn, which is data in the users
table. Yet we still have to get data from the restuarants
and foods
tables in order to create our user object.
We imagine that in the future half of our app's pages only need info from the users
table, while the other half of our app's pages need info from all 3 tables. Since we want our app to be fast and responsive, would it be a good idea to have our user
class only include things from the users
table, and then maybe create another class UserDetail
which includes the Food and Restaurant objects? On pages that we only need to display basic user table info, we use our User
class, and on pages where we need to display info about their favorite food and restaurant we use UserDetail
class? Or is there some other, better way to do this?
User
class, which is, in my opinion, too sketchy to qualify for a code review according to the rules in the help center. \$\endgroup\$User
class code looks like based on a small excerpt, but including theGreetSingleUserPage
is absolutely essential to the question, if that's the code that you want to have reviewed. Thanks for adding it. \$\endgroup\$