I've been a developer for many years, but have always put together files of lists of functions to do everything that needed to be done (instead of using classes/objects like I should be). I've recently started forcing myself to try to get into more object-oriented programming.
I wanted to get some feedback on whether or not I'm implementing classes/objects 'properly' and 'effectively'.
I'm manipulating "Questions" within "Surveys". "Questions" also have sub-parts such as "Choices", but all-in-all my classes are set up in the same format.
I have a Questions.class.php (which contains all items related to getting/setting/updating/deleting questions) and a QuestionList.class.php (which grabs lists of questions from the database).
<?php
//Question.class.php
class Question {
protected $_table;
public $_question;
public $lang;
function __construct($question_id) {
$this->_table = 'TABLE NAME OF QUESTIONS THEMSELVES';
$this->_surveys_table = 'TABLE NAME OF SURVEYS (A SURVEY CONTAINS QUESTIONS)';
//When I create an object in external code, I pass it either an ID of a question that exists in my database, or NULL to set up a blank question that doesn't yet exist in the database.
if(isset($question_id) && is_int($question_id)) {
$this->_question = $this->get($question_id);
} else {
$this->_question = array();
}
//This is just a file of error messages--stole the concept from a large Authentication class
require "language.php";
$this->lang = $lang;
}
//Literally just gets the question from the database and returns an error if it doesn't exist.
public function get($question_id) {
$return['error'] = true;
global $DBH;
$query = "SELECT * FROM {$this->_table} WHERE question_id = :question_id";
$q = $DBH->prepare($query);
$q->bindValue(':question_id', $question_id, \PDO::PARAM_INT);
$q->execute();
if(!$row = $q->fetch(\PDO::FETCH_ASSOC)) {
$return['message'] = $this->lang['questions_nomatch'];
return $return;
}
return $row;
}
//"Sets" the object into the object/fields array so that I can add it or use the object without actually saving to the database.
public function set($question, $question_multi, $survey_id) {
$return['error'] = true;
$this->_question = array(
'question' => $question,
'question_multi' => $question_multi,
'survey_id' => $survey_id
);
$return['message'] = $this->lang['questions_set'];
$return['error'] = false;
return $return;
}
//Adds a question to the database
public function add() {
$return['error'] = true;
$this->_question['question_order'] = $this->getOrder();
global $DBH;
//my database insert query is here.
if(!$q->execute()) {
$return['message'] = $this->lang['database_error'];
return $return;
}
$this->_question['question_id'] = $DBH->lastInsertId();
$this->incrementOrder($this->_question['question_order']);
$return['message'] = $this->lang['questions_added'];
$return['error'] = false;
return $return;
}
//I can use this to update a previously 'get' object (one that already exists in the database) in the database
public function update() {
$return['error'] = true;
global $DBH;
//my database update query is here.
if(!$q->execute()) {
$return['message'] = $this->lang['database_error'];
return $return;
}
$return['message'] = $this->lang['questions_updated'];
$return['error'] = false;
return $return;
}
//Deletes a question from the database.
public function delete() {
$return['error'] = true;
global $DBH;
$query = "DELETE FROM {$this->_table} WHERE question_id = :question_id";
$q = $DBH->prepare($query);
$q->bindValue(':question_id', $this->_question['question_id'], \PDO::PARAM_INT);
if(!$q->execute()) {
$return['message'] = $this->lang['database_error'];
return $return;
}
$return['message'] = $this->lang['questions_deleted'];
$return['error'] = false;
$return['delid'] = $this->_question['question_id'];
return $return;
}
}
?>
So, if I want to add a new question:
//this is how I create a question that doesn't exist in the database.
$_question = new Question(NULL);
$_question->set($question, $question_multi, $survey_id);
$add_question = $_question->add();
if(!$add_question['error']) {
//if there's no error adding, it now exists in the database and I do whatever
}
..or if I want to edit one that already exists:
//this is how I get a question that already exists from the database and update it to the database with new values
$question = new Question($question_id);
//I could also use $question->set($question, $question_multi, $survey_id) here but for some reason I refer the readability of this.
$question->_question['survey_id'] = $survey_id;
$question->_question['question'] = $question_question;
$question->_question['question_multi'] = $question_multi;
$question_updated = $question->update();
if(!$question_updated['error']) {
//the update was successful and I do whatever
}
And as for my QuestionList.class.php, it's much simpler but I'd also like to have feedback on if I'm using classes properly at all:
<?php
class QuestionList {
protected $_table;
public $_questionlist;
public $lang;
function __construct($survey_id) {
$this->_table = 'TABLE NAME OF QUESTIONS THEMSELVES';
require "language.php";
$this->lang = $lang;
//when created, I force the getAll function which either gets all values from the table or gets those with a specific survey_id
$this->_questionlist = $this->getAll($survey_id);
}
public function getAll($survey_id = NULL) {
$return['error'] = true;
global $DBH;
if($survey_id == NULL) {
$query = "SELECT * FROM {$this->_table} ORDER BY question_id";
$q = $DBH->prepare($query);
} else {
$query = "SELECT * FROM {$this->_table} WHERE survey_id = :survey_id ORDER BY question_order";
$q = $DBH->prepare($query);
$q->bindValue(':survey_id', $survey_id, \PDO::PARAM_INT);
}
$q->execute();
if(!$rows = $q->fetchAll(\PDO::FETCH_ASSOC)) {
$return['message'] = $this->lang['questions_notfound'];
return $return;
}
return $rows;
}
}
?>
To use it, I simply pass it NULL to get an entire list of EVERY question ever, or a survey_id to get specific questions from a Survey:
$question_list = new QuestionList($survey_id);
$questions = $question_list->_questionlist;
I know this is probably long and annoying, but I appreciate any feedback/suggestions!