I added in parent::__construct(); to the constructors of table and bookmark in order to get this code to work. Why are they not called automatically?
If I create an object of type bookmark $obj_ref_bo = new bookmark(); should not bookmark also create objects from each of its parent classes (besides abstract classes).
The call chain is
bookmark->table->database(abstract)->single_connect
/*single_connect*/
class single_connect
{
protected static $_db_pointer = NULL;
private function __construct()
{
$this->_db_pointer = mysql_connect(DB_HOST, DB_USER, DB_PASS);
mysql_select_db(DB_DATABASE);
}
public static function get_connection()
{
if(self::$_db_pointer == NULL)
{
return new self();
}
else
{
echo "Error:only one connection";
}
}
}
/*database*/
abstract class database
{
protected function __construct()
{
single_connect::get_connection();
}
static protected function query($query)
{
$result = mysql_query($query) or die(mysql_error());
return $result;
}
}
/*table*/
class table extends database
{
public $_protected_arr=array();
protected function __construct()
{
parent::__construct();
$this->protect();
}
protected function protect()
{
foreach($_POST as $key => $value)
{
$this->_protected_arr[$key] = mysql_real_escape_string($value);
}
}
}
/*bookmark*/
class bookmark extends table
{
function __construct()
{
parent::__construct();
$this->start();
}
function start()
{
if(this->test())
{
this->insert();
}
else
{
return 1;
}
}
function test()
{
if(this->test_empty())
{
return 1;
}
else
{
return 0;
}
}
function test_empty()
{
if(text::test_empty($this->_protected_arr))
{
return 1;
}
else
{
return 0;
}
}
function insert()
{
$url = $this->_protected_arr['url'];
$title = $this->_protected_arr['title'];
$email = $_SESSION['email'];
database::query("INSERT INTO bo VALUES ('$title', '$url', '$email')");
}
}
should not bookmark also create objects from each of its parent classes
That's entirely your choice to make, there is no requirement in the language to call the parent methods.
As the PHP manual concisely puts it:
Note: Parent constructors are not called implicitly if the child class defines a constructor. In order to run a parent constructor, a call to parent::__construct() within the child constructor is required.
— http://php.net/oop5.decon
While Java will call the no-arg constructor of the parent class if you don't call one specifically, PHP has no such feature. This allows you to do some work before calling the parent constructor, though you obviously shouldn't depend on any properties set by the parent constructor. ;)
BTW, as I stated in a comment, most of your calls that use self:: should be using $this-> instead. Only static methods are called using self::.
Related
I didn't find an answer to this question no where, so here it goes:
I normally create a protected/private function and public function as well to access the protected/private as a "trigger", is this a good practise or just a pointless excess of code?
Here is an example of what I'm talking about...
public function addData($data_c, $data_a)
{
if ($this->isUser()) {
$this->addDataDB($data_c, $data_a);
} else {
die;
}
}
private function addDataDB($data_c, $data_a)
{
$connect = self::connect_data();
$sql = "INSERT INTO `accounts`(...) VALUES (...)";
$s_network = $data_c['s_network'];
$country = $data_c['country'];
$group_name = $data_c['group_name'];
foreach ($data_a as $login_password) {
$account = explode(':', $login_password);
if (isset($account[0]) && !empty($account[0]) && isset($account[1]) && !empty($account[1])) {
$login = $this->encryptData($account[0]);
$password = $this->encryptData($account[1]);
if (!$this->checkDuplicates($login)) {
if ($stmt = $connect->prepare($sql)) {
$stmt->bind_param("sssssss", ...);
$stmt->execute();
}
$stmt->close();
}
}
}
$connect->close();
}
Thats not a bad idea, but the better way would be to create a new decorator class, which handles the secure access. In addition, it's a bad idea, to die - instead, you should throw an exception.
class A {
function addData(...) {
// ...
}
}
class SecureA extends A {
function addData {
if (...) {
throw new NotAllowedException(...);
}
parent::addData(...);
}
}
If you want to go a step further and make you code more cleaner, you should use an interface and don't extend from class A
interface InterfaceA {
function addData(...);
}
class A implements InterfaceA {
function addData(...) {
// ...
}
}
class SecureAccessA implements InterfaceA {
/**
* #var InterfaceA
*/
private $a;
public function __construct(InterfaceA $a) {
$this->a = $a;
}
function addData(...) {
if (...) {
throw new NotAllowedException(...);
}
$this->a->addData(...);
}
}
Doing this forces you to modify SecureAccessA, if you change the interface of InterfaceA. So you can't silently add functions to A, which are allowed to call, because you forgot to override them in the child class.
I have something like this:
class MyParent {
protected static $object;
protected static $db_fields;
public function delete() {
// delete stuff
}
public static function find_by_id($id = 0) {
global $database;
$result_array = self::find_by_sql("SELECT * FROM " . static::$table_name . " WHERE id=" . $database -> escape_value($id) . " LIMIT 1");
return !empty($result_array) ? array_shift($result_array) : false;
}
public static function find_by_sql($sql = "") {
global $database;
// Do Query
$result_set = $database -> query($sql);
// Get Results
$object_array = array();
while ($row = $database -> fetch_array($result_set)) {
$object_array[] = self::instantiate($row);
}
return $object_array;
}
private static function instantiate($record) {
$object = self::$object;
foreach ($record as $attribute => $value) {
if (self::has_attribute($attribute)) {
$object -> $attribute = $value;
}
}
return $object;
}
}
class TheChild extends MyParent {
protected static $db_fields = array('id', 'name');
protected static $table_name = "my_table";
function __construct() {
self::$object = new TheChild;
}
}
$child= TheChild::find_by_id($_GET['id']);
$child->delete();
I get this: Call to undefined method stdClass::delete() referring to the last line above. What step am I missing for proper inheritance?
You never actually instanciate the TheChild class, which should be done by
$var = new TheChild();
except in TheChild constructor itself.
So, the static $object field is never affected (at least in your example), so affecting a field to it (the line $object -> $attribute = $value; ) causes the creation of an stdClass object, as demonstrated in this interactive PHP shell session:
php > class Z { public static $object; }
php > Z::$object->toto = 5;
PHP Warning: Creating default object from empty value in php shell code on line 1
php > var_dump(Z::$object);
object(stdClass)#1 (1) {
["toto"]=>
int(5)
}
This object does not have a delete method.
And as said before, actually creating a TheChild instance will result in an infinite recursion.
What you want to do is this, probably:
class TheChild extends MyParent {
protected static $db_fields = array('id', 'name');
protected static $table_name = "my_table";
function __construct() {
self::$object = $this;
}
}
Edit: Your updated code shows a COMPLETE different Example:
class MyParent {
protected static $object;
public function delete() {
// delete stuff
}
}
class TheChild extends MyParent {
function __construct() {
self::$object = new TheChild;
}
}
$child = new TheChild;
$child->delete();
Calling "Child's" Constructor from within "Child's" Constructor will result in an infinite loop:
function __construct() {
self::$object = new TheChild; // will trigger __construct on the child, which in turn will create a new child, and so on.
}
Maybe - i dont know what you try to achieve - you are looking for:
function __construct() {
self::$object = new MyParent;
}
ALSO note, that the :: Notation is not just a different Version for -> - it is completely different. One is a Static access, the other is a access on an actual object instance!
I have this parent class in PHP:
class parentClass{
public $table;
public function __construct(){
$this->table = "my_parent_table";
}
public function getName($id) {
$strQuery = "SELECT name FROM $this->table WHERE id=$id";
$result = mysql_query($strQuery);
if ($result) {
$row = mysql_fetch_object($result);
if ($row) {
return $row->name;
} else {
return false;
}
} else {
return false;
}
}
}
And I have also another class with inherits this one:
class childClass extends parentClass{
public $table;
public function __construct(){
$this->table = "my_child_table";
}
}
Then in another file I am doing:
$myObj = new childClass();
$name = $myObj->getName('1');
The problem now is that the getName function has a null table, so the variable $this->table is null, while I want it to be ""my_child_table" as long as I have a childClass object.
Does anyone know what I am doing wrong?
Thanks in advance
Not sure, but this look tricky:
class childClass extends parentClass{
public $table;
The parentClass already defines a $table, so it's likely that redeclaring it inside the child class will clobber the parent's version. You have to remove the declaration here. Also, public visibility doesn't really encapsulate the state very well; use protected in the parent instead.
public function __construct()
{
You should add parent::__construct() here (unless parent only sets $this->table, but even then it's good to add)
$this->table = "my_child_table";
}
}
We have a class that holds a public array called $saved that contains lots of data required to share between methods (example below)...
class Common {
public $saved = array();
public function setUser($data) {
$this->saved['user_data'] = $data;
}
public function getUserID() {
return $this->saved['user_data']['id'];
}
}
There are literally thousands of lines of code that work like this.
The problem is that new instance of classes that extend Common are being made within some methods so when they access $saved it does not hold the same data.
The solution is to make $saved a static variable, however I can't change all of the references to $this->saved so I want to try and keep the code identical but make it act static.
Here is my attempt to make $this->saved calls static...
class PropertyTest {
private $data = array();
public function __set($name, $value) {
$this->data[$name] = $value;
}
public function __get($name) {
if (array_key_exists($name, $this->data)) {
return $this->data[$name];
}
return null;
}
public function __isset($name) {
return isset($this->data[$name]);
}
public function __unset($name) {
unset($this->data[$name]);
}
}
class Common {
public $saved;
private static $_instance;
public function __construct() {
$this->saved = self::getInstance();
}
public static function getInstance() {
if (self::$_instance === null) {
self::$_instance = new PropertyTest();
self::$_instance->foo = array();
}
return self::$_instance->foo;
}
}
This doesn't quite work when setting a variable it doesn't seem to stay static (test case below)...
class Template extends Common {
public function __construct() {
parent::__construct();
$this->saved['user_data'] = array('name' => 'bob');
$user = new User();
}
}
class User extends Common {
public function __construct() {
parent::__construct();
$this->saved['user_data']['name'] .= " rocks!";
$this->saved['user_data']['id'] = array(400, 10, 20);
}
}
$tpl = new Template();
print_r($tpl->saved['user_data']);
$this->saved is empty when User gets initialized and doesn't seem to be the same variable, the final print_r only shows an array of name => bob.
Any ideas?
First of all, I have to say that, IMO, it is not that good to use an instance's property as a class's property ($saved is not declared as static but its value is shared with all instance).
Here is a working version http://codepad.org/8hj1MOCT, and here is the commented code. Basically, the trick is located in using both ArrayAccess interface and the singleton pattern.
class Accumulator implements ArrayAccess {
private $container = array();
private static $instance = null;
private function __construct() {
}
public function getInstance() {
if( self::$instance === null ) {
self::$instance = new self();
}
return self::$instance;
}
public function offsetSet($offset, $value) {
if (is_null($offset)) {
$this->container[] = $value;
} else {
$this->container[$offset] = $value;
}
}
public function offsetExists($offset) {
return isset($this->container[$offset]);
}
public function offsetUnset($offset) {
unset($this->container[$offset]);
}
public function offsetGet($offset) {
return isset($this->container[$offset]) ? $this->container[$offset] : null;
}
}
class Common {
public $saved = null;
public function __construct() {
// initialize the "saved" object's property with the singleton
// that variable can be used with the array syntax thanks to the ArrayAccess interface
// so you won't have to modify your actual code
// but also, since it's an object, this local "$this->saved" is a reference to the singleton object
// so any change made to "$this->saved" is in reality made into the Accumulator::$instance variable
$this->saved = Accumulator::getInstance();
}
public function setUser($data) {
$this->saved['user_data'] = $data;
}
public function getUser() {
return $this->saved['user_data'];
}
}
class Template extends Common {
// you can redeclare the variable or not. Since the property is inherited, IMO you should not redeclare it, but it works in both cases
// public $saved = null;
public function __construct() {
// maybe we can move this initialization in a method in the parent class and call that method here
$this->saved = Accumulator::getInstance();
}
}
I think there are a number of issues with this implementation that could well come back to bite you. However, in your current implementation your contructing a new instance (albeit through a static call) every time.
Instead use getInstance() as your singleton hook, and make your __construct private, as you'll only be accessing it from with the context of the Common class.
Like so:
class Common {
public $saved;
private static $_instance;
private function __construct() {
}
public static function getInstance() {
if (self::$_instance === null) {
self::$_instance = new self();
... any other modifications you want to make ....
}
return self::$_instance;
}
}
And don't ever run parent::_construct(), instead always use the getInstance() method.
You might also want to ditch the idea of extending this singleton class. This is really a bad antipattern and could cost you a number of issues in the long run. Instead just maintain a Common class that other classes can read / write to. As its a singleton you don't need to worry about injection.
I seem to have solved the problem, by making $this->saved a reference to a static variable it works...
class Common {
private static $savedData = array();
public $saved;
public function __construct() {
$this->saved =& self::$savedData;
}
}
In a lot of my PHP classes, I have this code:
private $strError = "";
private $intErrorCode = NULL;
private $blnError = FALSE;
public function isError() {
return $this->blnError;
}
public function getErrorCode() {
return $this->intErrorCode;
}
private function setError( $strError, $intErrorCode = NULL ) {
$this->blnError = TRUE;
$this->intErrorCode = $intErrorCode;
$this->strError = $strError;
}
The point is so that outside code can know if an object has an error state, what the string of the error is, etc. But to have this exact code in a bunch of different classes is repetitious!
I'd love to have a dual-extension where I could do
class childClass extends parentClass, error {
...
}
And have those properties and methods inborn, But PHP doesn't support multiple inheritances. What I'm thinking about doing is creating an error class that exists inside each class. If I make it public, I can call it directly through the object
if ( $myObject->error->isError() ) {...}
but wouldn't that also make its error status settable from outside the containing class,
$myObject->error->setError("I shouldn't be doing this here");
which I would rather avoid?
Or I could write 'gateway' functions in the containing class, which do the appropriate calls on the error object, and prevent setting the error status from outside,
class childClass extends parentClass {
private $error;
public function __construct(...) {
...
$error = & new error();
...
}
public function isError() {...}
public function getError() {...}
public function getErrorCode() {...}
private function setError() {...}
...
}
but that leads to (some of) the code duplication that I'm trying to avoid.
What's the optimal solution here? I'm trying to have functionality for error statuses for a number of objects, so that the outside world can see their error state, with minimal repetition.
Use composition instead of inheritance.
class Errors {
private $strError = "";
private $intErrorCode = NULL;
private $blnError = FALSE;
public function isError() {
return $this->blnError;
}
public function getErrorCode() {
return $this->intErrorCode;
}
private function setError( $strError, $intErrorCode = NULL ) {
$this->blnError = TRUE;
$this->intErrorCode = $intErrorCode;
$this->strError = $strError;
}
}
And now use a private instance variable to refer to it:
class childClass extends parentClass {
private $errors = new Errors();
...
}
The private visibility prevents you from referencing $errors outside of the class.
There's also no need to create isError(), getError(), etc. inside childClass (and therefore no need to worry about code duplication). Simply call $this->errors->isError(), $this->errors->getError(), etc. If you still wanted to require those methods to be implemented though, as suggested below, you could specify an interface.
You could also abuse the __call magic method to do the same thing:
public function __call($name, array $arguments) {
$name = strtolower($name);
if (isset($this->methods[$name])) {
array_unshift($arguments, $this);
return call_user_func_array($this->methods[$name], $arguments);
}
throw new BadMethodCallException('Method does not exist');
}
Note that I said abuse... Ideally, I'd think of a different architecture rather than having all these "common methods" everywhere. Why not use an exception instead of checking $foo->isError? If that's not appropriate, why not decorate a class?
class Errors
protected $object = null;
public function __construct($object) {
$this->object = $object;
}
public function __call($method, array $arguments) {
$callback = array($this->object, $method);
if (is_callable($callback)) {
return call_user_func_array($callback, $arguments);
}
throw new BadMethodCallException('Method does not exist');
}
public function __get($name) { return $this->object->$name; }
public function __set($name, $value) { $this->object->$name = $value; }
// Your methods here
public function isInstance($name) { return $this->object instanceof $name; }
}
Then just "wrap" your existing object in that class:
$obj = new Errors($obj);
$obj->foo();
As of PHP 5.4, you can use Traits.
For example you could make Trait called ErrorTrait like this:
trait ErrorTrait {
private $strError = "";
private $intErrorCode = NULL;
private $blnError = FALSE;
public function isError() {
return $this->blnError;
}
public function getErrorCode() {
return $this->intErrorCode;
}
private function setError( $strError, $intErrorCode = NULL ) {
$this->blnError = TRUE;
$this->intErrorCode = $intErrorCode;
$this->strError = $strError;
}
}
Then you would define your child class like this:
class childClass extends parentClass {
use ErrorTrait;
...
}
Traits work basically like copy/paste so all of the code in the trait would be available within the class (without the code duplication).