Any advice is welcome!
I have a very limited understanding of php classes but below is my starting point for the route I would like to take. The code is a reflection of what I see in my head and how I would like to go about business. Does my code even look ok, or am I way off base?
What are your thoughts, how would you go about achieving such a task as form->validate->insertquery->sendmail->return messages and errors?
Please try and keep your answers simple enough for me to digest as for me its about understanding whats going on and not just a copy/paste job.
Kindest regards,
Phil.
Note: This is a base structure only, no complete code added.
<?php
//=======================================
//class.logging.php
//========================================
class logging
{
public $data = array();
public $errors = array();
function __construct()
{
array_pop($_POST);
$this->data =($this->_logging)? is_isset(filterStr($_POST) : '';
foreach($this->data as $key=> $value)
{
$this->data[$key] = $value;
}
//print_r($this->data); de-bugging
}
public function is_isset($str)
{
if(isset($str)) ? true: false;
}
public function filterStr($str)
{
return preg_match(do somthing, $str);
}
public function validate_post()
{
try
{
if(!is_numeric($data['cardID'])) ? throw new Exception('CardID must be numeric!') : continue;
}
catch (Exception $e)
{
return $errors = $e->getCode();
}
}
public function showErrors()
{
foreach($errors as $error => $err)
{
print('<div class="notok"></div><br />');
}
}
public function insertQ()
{
$query = "";
}
}
//=======================================
//Usercp.php
//========================================
if(isset($_GET['mode']))
{
$mode = $_GET['mode'];
}
else
{
$mode = 'usercp';
}
switch($mode)
{
case 'usercp':
echo 'Welcome to the User Control Panel';
break;
case 'logging':
require_once 'class.logging.php';
$logger = new logging();
if(isset($_POST['submit'])
{
if($logger->validate_post === true)
{
$logger->insertQ();
require_once '/scripts/PHPMailer/class.phpmailer.php';
$mailer = new PHPMailer();
$mailer->PHPMailer();
}
else
{
echo ''.$logger->showErrors.'';
}
}
else
{
echo
'
<form action="'.$_SERVER['PHP_SELF'].'?mode=logging" method="post">
</form>
';
}
break;
case 'user_logout':
// do somthing
break;
case 'user_settings':
// do somthing
break;
?>
I have decided to use this method for returning errors rather than print them in the method, thanks for the advice Igor!
catch (Exception $e)
{
$this->errors[] = $e->getMessage();
#ERROR DE_BUGGING ONLY================================
#print('<pre>');
#print_r($this->errors);
#print('</pre>');
#=====================================================
}
if($this->errors)
{
return false;
}
else
{
return true;
}
It looks like you have a decent understanding of OOP code. I see declared public vars and even try/catches, though I'd say don't forget the "public" visibility keyword in front of "function __construct()"—not absolutely necessary, but it keeps with good coding practices.
Further, I would say that everything you are doing here has been written, debugged, and fixed, and proven production worthy already by each of the dozens of PHP frameworks out there. The specific task you mentioned, "form->validate->insertquery->sendmail->return messages and errors" is so incredibly easy with Zend Framework, my framework of choice. And I would imagine the same is true for Symphony, Solar, Cake, etc.
Do yourself a favor and stop coding what has been coded already. Learn a framework that has a community, regular updates, and well-written thorough documentation. Again, I recommend Zend Framework.
First advice that comes to mind: Separate logic from presentation. You can start by using some template engine like Smarty. If you will keep it all mixed up, soon it will be a huge dump.
Also try to include class definitions from separate files, and as a next step I would recommend adopting some pattern like Model-View-Controller to separate models from logic.
That's what I can think of without digging too deep into the code.
Related
<?php
function loadModule($module,$action=null,$param=null){
$access_group = $_SESSION['access_group'];
$auth_controller = new auth();
if($auth_controller->check_access($module,$action)){
if (!class_exists($module)) {
include "modules/" . $module . "/controller/controller.php";
}
$controller = new $module();
if ($action) {
if ($param) {
return $controller->{$action}($param);
} else {
return $controller->{$action}();
}
} else {
return $controller->index();
}
}else{
if (!class_exists("forbidden")) {
include_once "modules/forbidden/controller/controller.php";
}
$forbidden_controller = new forbidden();
$forbidden_controller->view->render();
}
i seen a func like this , i dont know what happen in line 14 and 16 give me a hand and explain it.
i want to know how and where we should use this kind of codes
You're talking about this line:
$controller->{$action}();
This it less complex than it looks. You're used to the syntax of normal class method calls, like this:
$controller->getOrderNumber();
In the code in your question the method name has been replace by a variable.
See example 2 here.
Note that the two lines below are equivalent:
$controller->{$action}();
$controller->$action();
I would use variable method names very sparingly. They make reading code and debugging more difficult. On top of that they might pose a security risk.
Recently I started to write PHPUnit test. And this is my model code.(I used CodeIgniter 3).
Account_model.php
class Account_model extends CI_Model
{
...
public function select_by_seq($seq = '', $select_columns = [])
{
try {
$bind = [':a_seq' => $seq];
// check $select_colums is exist in table
if ($this->check_column($select_columns) === false)
{
throw new Exception('columns illegal', 201);
}
...
$sql = "select ....
from {$this->db->dbprefix('account')}
where a_seq = :a_seq";
$query = $this->db->query($sql, $bind);
// ===== this always not runing. =====
if ($query === false)
{
// ===== this always not runing. =====
throw new Exception('sql errors', 301);
}
else
{
return $query->result_array();
}
}
catch (Exception $error)
{
// set error log
$this->set_error_log($error->getCode() . $error->getMessage());
}
return false;
}
}
This is my test Account_model_test.php
class Account_model_test extends TestCase
{
public static function setUpBeforeClass()
{
parent::setUpBeforeClass();
$CI =& get_instance();
}
public function setUp()
{
$this->resetInstance();
loader('model', 'account_model');
$this->obj = $this->CI->account_model;
}
public function test_select_by_seq()
{
$result = $this->obj->select_by_seq(
$seq = '20160830'
);
$this->assertCount(1, $result);
}
public function test_select_by_seq_with_illegal_column()
{
$result = $this->obj->select_by_seq(
$seq = '20160830',
$select_columns = ['illegal']
);
$this->assertFalse($result);
}
...
}
Because I write SQL by myself. I founded my PHPUnit test can't cover this if ($query === false). And then my code coverage didn't achieve 100%. This problem let me think the 100% is very important for the unit test? Or I had to modify my model code? Thanks your help.
It's good to always have code coverage 100%. But like you said there are situations when this is very hard to achieve. So having code coverage greater than 70% is quite good for most of the projects. See this link regarding the minimum code coverage required in project. But you should try to extract your business logic to its own class (Repository) and unit test it.
It would be good if you show us your test file also, so we can be more clear about what you already have there.
Without knowing that, what I can suggest is to use Mock of query function, so it can return false as result. You can find more about Mocks here
Also as written before: you should not focus on 100% code coverage.
The #codeCoverageIgnore, #codeCoverageIgnoreStart and #codeCoverageIgnoreEnd annotations can be used to exclude lines of code from the coverage analysis. -- PHPUnit Manual
There are examples in the PHPUnit documentation.
In a nutshell, wrap the code to be ignored by code coverage in *Start *End annotations:
if (false) {
// #codeCoverageIgnoreStart
print '*';
// #codeCoverageIgnoreEnd
}
Also see What is a reasonable code coverage % for unit tests (and why)?.
here is what im doing
im using
pthreads from - pthreads.org
php Simple Html DOM parser from - simplehtmldom.sourceforge.net
now the process of what i (will) do is:
I am reading a bulk of links that is from a text file.
I initialize a thread to have a separate process
I am creating a log file for this thread so that i will know, what happens later on.
now, this is my code for my thread class.
class ReadLinks extends Thread {
private $conn;
private $links;
private $fileObj;
public function __construct($conn, $links, $fileObj) {
//.. well just asign this to the global variables
}
public function run() {
try {
$this->logMsg("Start Reading Reviews");
$this->readLinks();
} catch (Exception $ex) {
$this->logMsg($ex);
}
$this->closeLog();
}
private function readLinks() {
$this->logMsg("Links");
foreach ($this->links as $link) {
$link = trim(preg_replace('/\s\s+/', ' ', $link));
$this->logMsg("Link: " . $link);
$html = html_readLink($link);
break;
}
}
private function logMsg($msg) {//something to write on the text file
}
private function closeLog() {//closes the textfile
}}
$conn - is my mysqli link to have db actions in the future
$links - is an array of links to be read.
$fileObj- is a resource return from fopen(). ( well to write into a file)
now who is that html_readlink,
its an outer function that is like this:
function html_readLink($link) {
return file_get_html($link);}
basically it is the resource returned by a function from simple html dom parser
now, i have as well a function that reads a link alone to do the other (different business requirement) and im using the simple html dom parser with ease.
with the pthreads, i tried writing the file(logs first) so that i can ensure that everything as well works fine.
about contacting db is not yet sure., well ill try to figure it out if it works fine, but logically it should work.
now when i called this class: its like this:
try {
$thread = new readLinks($conn, $Links, createlog());
if ($thread->start()) {
$thread->join();
} else {
echo "something i need to research if this happens";
}
} catch (Exception $err) {
echo $err; //something i need to research as well if this happens
}
i got this error
Warning: Invalid argument supplied for foreach() in C:\my\path\to\simplehtmldom_1_5\simple_html_dom.php on line 1119
that simplehtmldom code is:
function clear()
{
foreach ($this->nodes as $n) {$n->clear(); $n = null;}
// This add next line is documented in the sourceforge repository. 2977248 as a fix for ongoing memory leaks that occur even with the use of clear.
if (isset($this->children)) foreach ($this->children as $n) {$n->clear(); $n = null;}
if (isset($this->parent)) {$this->parent->clear(); unset($this->parent);}
if (isset($this->root)) {$this->root->clear(); unset($this->root);}
unset($this->doc);
unset($this->noise);
}
now that is the source code coming from simple html dom. that foreach is the one that is returning the error. now my other code using simple html dom doesn't have a problem with simple html dom. but with pthreads i got this error.
also, when i change my codes and didn't use pthreads, (had some revisions like this:
on pthreads class:
class ReadLinks {// extends Thread {
//insert other codes
public function readLinks() {
$this->logMsg("Links");
foreach ($this->links as $link) {
$link = trim(preg_replace('/\s\s+/', ' ', $link));
$this->logMsg("Link: " . $link);
$html = html_readLink($link);
$this->logMsg(getTitle($html));
//
break;
}
}
and change the way this is called like this:
try {
$thread = new ReadLinks($conn, $revLinks, createlog());
$thread->readLinks();
// if ($thread->start()) {
// $thread->join();
// } else {
// echo "something i need to research if this happens";
// }
} catch (Exception $err) {
echo $err; //something i need to debug and research if this happens
}
everything works fine, i get the desired results.
pthreads is something i need to use since loading bulk links and reading each of them is quite a time consuming process. and i need it to be on a separate thread. now i dont know whats wrong with these pthreads, or simple html dom parser. have i done something unnecessary/wrong? is there other way to do this?
anyone??
EDIT
i followed the answer of Prafulla Kumar Sahu:
the new code for the function clear() of simple html dom is:
function clear() {
if (is_array($this->nodes) || $this->nodes instanceof Traversable) {
foreach ($this->nodes as $n) {
$n->clear();
$n = null;
}
}
// This add next line is documented in the sourceforge repository. 2977248 as a fix for ongoing memory leaks that occur even with the use of clear.
if (isset($this->children))
foreach ($this->children as $n) {
$n->clear();
$n = null;
}
if (isset($this->parent)) {
$this->parent->clear();
unset($this->parent);
}
if (isset($this->root)) {
$this->root->clear();
unset($this->root);
}
unset($this->doc);
unset($this->noise);
}
the result is: it eliminated the error
but it is not the desired result
when using the function
$x=$resource->find($selector,0);
//resource is the return obj of file_gets_content, selector is my css selector string
it returns null/empty where in fact it should have a value.
ive checked a separate function that uses the simple html dom after i updated their code, seems it wasn't affected, and it is working properly. but with my pthread class, it is not working correctly.
The code I have doesn't have a foreach on line 1119; maybe you have an older version. You're getting a warning only, what problem(s) do you see in the results?
1117 // save dom as string
1118 function save($filepath='')
1119 {
1120 $ret = $this->root->innertext();
1121 if ($filepath!=='') file_put_contents($filepath, $ret, LOCK_EX);
1122 return $ret;
1123 }
It happens if the variable you are trying to traverse using foreach is not irritable so please check if your variable is either an array or instanceof Traversable class .
*It may be because you are not getting any value for that variable you want to traverse.
so, I would suggest you to use is_array( $whatever ) || $whatever instanceof Traversable just before foreach.
ie.
if( is_array( $whatever ) || $whatever instanceof Traversable ){
foreach( $whatever as $what ){
//some code
}
}
In your case it is
function clear()
{
foreach ($this->nodes as $n) {$n->clear(); $n = null;}
// This add next line is documented in the sourceforge repository. 2977248 as a fix for ongoing memory leaks that occur even with the use of clear.
if (isset($this->children)) foreach ($this->children as $n) {$n->clear(); $n = null;}
if (isset($this->parent)) {$this->parent->clear(); unset($this->parent);}
if (isset($this->root)) {$this->root->clear(); unset($this->root);}
unset($this->doc);
unset($this->noise);
}
source:- https://github.com/jalbertbowden/simplehtmldom/blob/master/simplehtmldom_1_5/simple_html_dom.php#L1119
this means you are unable to get $this->nodes correctly, so please var_dump it before you are calling function clear or before the foreach .
I was wondering if someone can show me a good way to handle errors in my PHP app, that i am also easily able to reuse in my other scripts.
So far i have been using the following functions:
Inline Errors
function display_errors_for($fieldname) {
global $errors;
if (isset($errors[$fieldname]))
{
return '<label for="' .$fieldname. '" class="error">' . ucfirst($errors[$fieldname]). '</label>';
} else {
return false;
}
}
All Errrors
function display_all_errors($showCounter = true) {
global $errors;
$counter = 0;
foreach ($errors as $errorFieldName => $errorText)
{
if ($showCounter == true)
{
$counter++;
echo '<li>' . $counter . ' - <label for="' .$errorFieldName. '">' .$errorText. '</label></li>';
} else {
echo '<li><label for="' .$errorFieldName. '">' .$errorText. '</label></li>';
}
}
}
I have a $errors = array(); defined on the top of my global file, so it is appended to all files.
The way i use it is that, if i encounter an error i push a new error key/value to the $errors array holder, something like the following:
if (strlen($username) < 3) {
$errors['username'] = "usernames cannot be less then 3 characters.";
}
This all works great and all, But i was wondering if some one has a better approach for this? with classes? i don't think i want to use Exceptions with try/catch seems like an overkill to me.
I'm planning to make a new app, and i'll be getting my hands wet with OOP alot, though i have already made apps using OOP but this time i'm planning to go even deeper and use OOP approach more extensively.
What i have in mind is something like this, though its just a basic class i will add further detail to it as i go deeper and deeper in my app to see what it needs.
class Errors
{
public $errors = array();
public function __construct()
{
// Initialize Default Values
// Initialize Methods
}
public function __destruct()
{
//nothing here too...
}
public function add($errorField, $errorDesc)
{
if (!is_string($errorField)) return false;
if (!is_string($errorDesc)) return false;
$this->errors[$errorField] = $errorDesc;
}
public function display($errorsArray)
{
// code to iterate through the array and display all errors.
}
}
Please share your thoughts, if this is a good way to make a reusable class to store and display errors for an entire app, or is getting more familiar with exceptions and try/catch my only choice?
I cannot imagine a reason for creating a distinct class for as trivial task as echoing several text strings into browser.
Or I am missing something.
I see no point for the function even.
Personally I have in my templates (where I need it) the code block like this
<? if ($data['errors']): ?>
<div class="errors">
<ul>
<? foreach ($data['errors'] as $e): ?>
<li><?=$e?></li>
<? endforeach ?>
</ul>
</div>
<? endif ?>
and find it quite enough
If you are into OOP, you should use framework like Zend Framework. In ZF there is an action helper for general error/result messages: FlashMessenger
http://framework.zend.com/manual/en/zend.controller.actionhelpers.html#zend.controller.actionhelpers.flashmessenger
I tried to ask this before, and messed up the question, so I'll try again. Is it possible to make an object return false by default when put in an if statement? What I want:
$dog = new DogObject();
if($dog)
{
return "This is bad;"
}
else
{
return "Excellent! $dog was false!"
}
Is there a way this is possible? It's not completely necessary, but would save me some lines of code. thanks!
No, PHP has no support for operator overloading. Maybe they'll add it in a future version.
Use the instanceof keyword.
For example
$result = Users->insertNewUser();
if($result instanceof MyErrorClass){
(CHECK WHAT WENT WRONG AND SAY WHY)
} else {
//Go on about our business because everything worked.
}
Info is here.
Use this? Not a real neat solution, but does what you want:
<?php
class Foo
{
private $valid = false;
public function Bar ( )
{
// Do stuff
}
public function __toString ( )
{
return ( $this -> valid ) ? '1' : '0';
}
}
?>
Zero is considered false, one is considered true by PHP
I was attempting to do this myself and found a solution that appears to work.
In response to the others who were trying to answer the question by telling the asker to use a different solution, I will also try to explain the reason for the question. Neither the original poster or I want to use an exception, because the point is not to use exception handling features and put that burden on any code we use this class in. The point, at least for me, was to be able to use this class seamlessly in other PHP code that may be written in a non-object-oriented or non-exception-based style. Many built-in PHP functions are written in such a way that a result of false for unsuccessful processes is desirable. At the same time, we might want to be able to handle this object in a special way in our own code.
For example, we might want to do something like:
if ( !($goodObject = ObjectFactory::getObject($objectType)) ) {
// if $objectType was not something ObjectFactory could handle, it
// might return a Special Case object such as FalseObject below
// (see Patterns of Enterprise Application Architecture)
// in order to indicate something went wrong.
// (Because it is easy to do it this way.)
//
// FalseObject could have methods for displaying error information.
}
Here's a very simple implementation.
class FalseObject {
public function __toString() {
// return an empty string that in PHP evaluates to false
return '';
}
}
$false = new FalseObject();
if ( $false ) {
print $false . ' is false.';
} else {
print $false . ' is true.';
}
print '<br />';
if ( !$false ) {
print $false . ' is really true.';
} else {
print $false . ' is really false.';
}
// I am printing $false just to make sure nothing unexpected is happening.
The output is:
is false.
is really false.
I've tested this and it works even if you have some declared variables inside the class, such as:
class FalseObject {
const flag = true;
public $message = 'a message';
public function __toString() {
return '';
}
}
A slightly more interesting implementation might be:
class FalseException extends Exception {
final public function __toString() {
return '';
}
}
class CustomException extends FalseException { }
$false = new CustomException('Something went wrong.');
Using the same test code as before, $false evaluates to false.
I recently had to do something similar, using the null object pattern. Unfortunately, the null object was returning true and the variable in question was sometimes an actual null value (from the function's default parameter). The best way I came up with was if((string)$var) { although this wouldn't work for empty arrays.
Putting something in "an if statement" is simply evaluating the variable there as a boolean.
In your example, $dog would need to be always false for that to work. There is no way to tell when your variable is about to be evaluated in a boolean expression.
What is your ultimate purpose here? What lines of code are you trying to save?
I'm not sure about the object itself. Possible. You could try something like, add a public property to the DogObject class and then have that set by default to false. Such as.
class DogObject
{
var $isValid = false;
public function IsValid()
{
return $isValid;
}
}
And then when you would instantiate it, it would be false by default.
$dog = new DogObject();
if($dog->IsValid())
{
return "This is bad;"
}
else
{
return "Excellent! $dog was false!"
}
Just a thought.
If I understand what your asking, I think you want to do this:
if (!$dog){
return "$dog was false";
}
The ! means not. SO you could read that, "If not dog, or if dog is NOT true"
Under what conditions do you want if($dog) to evaluate to false? You can't do what you've literally asked for, but perhaps the conditioned could be replaced by something that does what you want.
class UserController
{
public function newuserAction()
{
$userModel = new UserModel();
if ($userModel->insertUser()) {
// Success!
} else {
die($userModel->getError());
}
}
}
Or
class UserController
{
public function newuserAction()
{
$userModel = new UserModel();
try {
$userModel->insertUser()
}
catch (Exception $e) {
die($e);
}
}
}
There are a million ways to handle errors. It all depends on the complexity of the error and the amount of recovery options.
How about using an Implicit Cast Operator like the following C# ?
like so:
class DogObject
{
public static implicit operator bool(DogObject a)
{
return false;
}
}
Then you can go...
var dog = new DogObject();
if(!dog)
{
Console.WriteLine("dog was false");
}