I'm developing a club membership register web application and I am a fairly newbie when it comes to oop. The problem I'm having is that I would need to call a function outside a class, but I know you can't do that in PHP and I need to solve it somehow.
This code will demonstrate what my problem is:
members.php
class member {
private $id;
private $member_num;
private $name;
...
...
public function __construct() {
$a = func_get_args();
$i = func_num_args();
if (method_exists($this,$f='__construct'.$i)) {
call_user_func_array(array($this,$f),$a);
}
}
private function __construct1($f_id) { // Construct object by id-number
// Code to retrieve the data from database
}
I've written the code for database actions in a separate file called database_functions.php, but I can't include that file inside a class. What I need to know is how can I access those functions without having to write them again inside the class? (I have written applications before with VB.Net and in it I can use functions of the current project inside classes.)
You can extend a class to another class to access parent class functions and properties in subclass. Functions declared private cannot be accessed like that. You can also pass object of another class to to one class as an argument to the constructor.
if you have a class name parent :
class parent{
// properties and methods
}
Then you can access its functions if you extend it to your class :
class child extends parent{
// code
}
OR
$parent = new parent();
$child = new child($parent);
Then in child class you can use :
function __construct($parent) {
$this->connection = $parent;
}
Then within other functions in child class you can access the parent class methods using
$parent->connection->function_name()
you can use require_once() with exact path of that class after that you should use the object of the included class and function name for calling the function of outer class.
if(file_exists($class_path))
{
require_once($class_path);
$cl_obj = new name_of_class();
$outer_class_result = call_user_func_array(array($cl_obj,$function_name),$parametrs);
}
If you have a main file that calls different files (via include or require), then you can use any function that will exist in global namespace just fine in that class, provided the function you call will always exist in global namespace.
At the top of your class file, for instance, you could call another file with use of require_once. (Just to be sure you never include the same file twice, it's always good to use include_once and require_once.)
The other options is to wrap the other functions you have inside another class, provided that it makes sense. Class A could then hold a field with a class B object and call B's functions as it pleases.
class classA {
private $BInstance;
function __construct($b) {
$this->BInstance = $b;
}
function some_call($input) {
if($this->valid_input($input)) {
$this->BInstance->transform($input);
}
}
}
The benefit of this is that everything is abstracted in classes. Once you're outside of the class, all you have to know is what methods (functions) you can use of a class and you won't have to worry about the implementation details. A direct advantage of this is that you don't have to pass the same parameter to same functions all the time, say, if you need a database handler to execute SQL code within a function. A class could just hold such an instance and you won't have to repeat the same parameter all the time.
An additional advantage is that your global namespace won't be polluted with specific functions.
I'm not sure if you include the file which defined the functions you want.
I tried this with my symfony preject and it works well.
The test.php contains a function.
<?php
function double_number($value)
{
return $value*2;
}
?>
and I include it in the Model:
include(__DIR__.'/test.php');
class HomeModel
{
...
public function __construct()
{
$this->preExecute();
echo double_number(5);
exit;
}
...
}
and it output whith 10.
Maybe you need the include the file I think.
In my opinion here is one solution :-
Make your file('database_functions.php') a class containing all your functions. Like..
class mydbcls{
public function function_1(){}
public function function_2(){}
public function function_3(){}
//......
public function function_n(){}
}
Now when you are writing your class which is named as "member", write it in such a way that it extends your mydbcls.
class member extends mydbcls{
private $id;
private $member_num;
private $name;
...
...
public function __construct() {
$a = func_get_args();
$i = func_num_args();
if (method_exists($this,$f='__construct'.$i)) {
call_user_func_array(array($this,$f),$a);
}
}
private function __construct1($f_id) { // Construct object by id-number
// Code to retrieve the data from database
// Now you can access your database functions in this way
// $this->function_1();
}
now you can access your db functions this way
$this->function_1();
Related
Looking for a clean way to determine the class (in this case, either parent or child class) of the method that calls a method in the parent class.
I thought late static binding could handle this, but seems like that only really works for calling a static method directly, and not from within an instantiated object's method.
Consider the following:
abstract class ParentClass {
public function parentMethod() {
self::_log("parent.non.static");
}
public static function parentStatic() {
self::_log("parent.static");
}
public static function getClassName() {
return __CLASS__;
}
protected static function _log($key) {
$prefix = 'graphite.key.prefix';
$class = static::getClassName(); // gets the object's class, not calling class
$g_key = "{$prefix}.{$class}.{$key}";
echo "{$g_key} \n";
// Graphite::increment($g_key);
}
}
class ChildClass extends ParentClass {
public function childMethod() {
self::_log("child.non.static");
}
public static function childStatic() {
self::_log("child.static");
}
public static function getClassName() {
return __CLASS__;
}
}
$obj = new ChildClass;
$obj->childMethod(); // graphite.key.prefix.ChildClass.child.non.static
$obj->parentMethod(); // graphite.key.prefix.ChildClass.parent.non.static
ParentClass::parentStatic(); // graphite.key.prefix.ParentClass.parent.static
ChildClass::childStatic(); // graphite.key.prefix.ChildClass.child.static
Looking for a clean way to get the class that calls the _log() method without having to pass it in as a parameter. Doesn't have to be static at all, but I was playing around with the late static binding, because I thought that would work, but it just gets the name of the instantiated object, not the child/parent class of the method that calls the _log() method :-/
Edit:
Just to be clear, I'm after getting the class name of the method that called _log() from within the instantiated object (like parentMethod() and childMethod()) Don't care if _log() is static or not. If that makes it easier, fine. But the static ParentClass::parentStatic() and ChildClass::childStatic() were just to show late static bindings and what I figured might work, but not from calling within an instantiated object
http://php.net/manual/en/function.get-called-class.php
class One {
public static function test() {
echo get_called_class() . PHP_EOL;
}
}
class Two extends One {}
One::test();
Two::test();
Output:
One
Two
Also, according to the top comment in the docs static::class also works as of PHP 5.5.
get_class will get the class name of a class instance. This can also be called on $this within a class. If you have a class that extends/implements another, $this will refer the the instantiated class, meaning the child class.
Another option is to use debug_backtrace to get the stack of functions that lead up to where you currently are. You can parse the returned array to get whatever you need including line numbers, classes, functions, methods, whatever.
I just have a simple question here... I was working on developing a forum application for my website, and while updating some of the old methods I used (my old code is horrid) I came across - not for the first time - OOP devices.
I have quite a few classes that my system uses, and redefining the same function(s) for them over and over, so I decided to create a base class that would carry the functionality.
I've been trying to use require() on the base class then extend the class off of it...
<?php
require(//path to base class);
class User extends BaseClass {
// code
}
?>
But I don't know how to check if it's there, and it doesn't seem to be inheriting the base class's only function...
public function __get($what) {
if(property_exists($this, $what)) {
return $this->{$what};
} else {
return null;
}
}
Since when I try to retrieve a variable from the User class (e.g. $user->Username) it returns NULL. The variable is marked as private in the class, but before I tried to do inheritance that wasn't an issue.
It sounds like you are wanting to get after your variables in your parent class but do not want to use getter methods to do so. Marking these variables protected will indeed allow your child classes access to those properties, but in cases where you want your base class to enforce processing before setting/getting, marking the properties protected will not cut it.
In your case it sounds like you are marking your variables protected as a workaround. However you can still use private variables in your base class and allow access to them in your child classes as follows:
class BaseClass
{
private $strValue = "We the people....";
public function __get($what)
{
if(isset($this->{$what})) {
return $this->{$what};
}
return null;
}
}
class ChildClass extends BaseClass
{
private $intValue = 255;
public function __get($what)
{
if(isset($this->{$what})) {
return $this->{$what};
} else if(parent::__get($what) != null) {
return parent::__get($what);
}
return null;
}
}
//Try it out
$child = new ChildClass();
var_dump($child->strValue); //"We the people...."
var_dump($child->intValue); //255
In this example the BaseClass uses the __get() magic method to lookup its own properties and the ChildClass overrides it to do the same. In the ChildClass if it cannot find a requested property, then it diverts to the parent's version.
As long as you don't override your properties you can use private variables throughout and access them as if they were public outside of your class scope.
just use
class_exists() to make sure your class is there.
This might be basic knowledge, but I am curious as I do not know it yet myself. Why in PHP (and assuredly other languages) when using classes must a child class use a construct method to access the parent class' properties. In case this is unclear I will include an example.
<?php
class aClass
{
protected $aProperty = "Some value";
}
class aDifferentClass extends aClass
{
public $aDifferentProperty;
public function __construct()
{
$this->$aDifferentProperty = $this->aProperty;
}
?>//Works.
Instead of:
<?php
class aClass
{
protected $aProperty = "Some value";
}
class aDifferentClass extends aClass
{
public $aDifferentProperty = $this->$aProperty;
}
?>//Doesn't work.
Its not a matter of needing the constructor its a matter of WHEN you're trying to access it. A class is a blueprint for an object -- when you're trying to assign the property, as you've done in your example above, ie.
public $aDifferentProperty = $this->aProperty;
There is no object, and thus "this" does not yet exist. But, instead, this would work:
class A {
protected $a_property = "BOOYEA!";
}
class B extends A {
public function show_me_a_prop() {
echo $this->a_property;
}
}
$object = new B();
$object->show_me_a_prop();
So, to answer your question, you must wait until after the object has been constructed to access the properties because until its constructed, its not an object, just a blueprint for an object.
Now, to take this a bit further, you'd not allowed to assign variables directly to properties (see http://php.net/manual/en/language.oop5.properties.php ) but you can assign a constant. So here's a similar example which does work:
class A {
const a_property = "BOOYEA!";
}
class B extends A {
public $b_property = self::a_property;
}
$object = new B();
echo $object->b_property;
The "__construct" was introduced in PHP5 and it is the right way to define your constructors (in PHP4 you used the name of the class for a constructor).
You are NOT REQUIRED to define a constructor in your class, but if you wish to pass any parameters on object construction THEN YOU NEED ONE.
Also...If further down the track you change the class the child class inherits from, you don't have to change the construct call to the parent.
much easier to call parent::__construct() instead of parent::ClassName(), as it is reusable among classes and the parent can be changed easily.
I've seen a few questions with really similar titles but they where irrelevant to my specific problem.
Basically, I want to access the variables from my core class in a class which extends core, but things seem to be quite complicated compared to other examples. I am using a MVC framework. I've simplified the code below to remove anything that was irrelevant.
index.php
// Load the core
include_once('core.php');
$core = new Core($uri, $curpath);
$core->loadController('property');
core.php
class Core
{
public $uri;
public $curpath;
function __construct($uri, $curpath)
{
$this->uri = $uri;
$this->curpath = $curpath;
}
// Load the controller based on the URL
function loadController($name)
{
//Instantiate the controller
require_once('controller/'.$name.'.php');
$controller = new $name();
}
}
property.php
class Property extends Core
{
function __construct()
{
print $this->curpath;
}
}
Printing $this->curpath just returns nothing. The variable has been set but it is empty.
If I print $this->curpath inside core.php it prints fine.
How can I access this variable?
You are doing it wrong tm
You should be utilizing an autoloader, instead of including files with each class manually. You should learn about spl_autoload_register() and and namespaces, and how to utilize both of them.
Do not generate output in the __construct() methods. That's an extremely bad practice
The variables are still there. That is not the problem. In PHP, when you extend a class, it does not inherit the constructor.
You do not understand how inheritance works. When you call method on instance of extended class it will not execute parent class's method , before calling extended class's methods. They get overwritten , not stacked.
Object variables should not be exposed. You are breaking the encapsulation. Instead og defining them as public you should use protected.
You should extend classes of they are different type same general thing. The extends in PHP means is-a. Which means that, when you write class Oak extends Tree, you mean that all the oaks are trees. The same rule would mean, that in your understanding all Property instances are just a special case of Core instances. Which they clearly ain't.
In OOP, we have principle. One of which is Liskov substitution principle (shorter explanation). And this is the thing your classes are violating.
The problem, I think, lies here:
If you consider a simple inheritance like this one:
class Dog{
public $color;
public function __construct($color){
$this->color = $color;
}
}
class TrainedDog extends Dog{
public $tricks;
public function __construct($color, $tricks){
$this->tricks = $tricks;
parent::__construct($color);
}
}
//Create Dog:
$alfred = new Dog('brown');
//Create TrainedDog
$lassie = new TrainedDog('golden',array('fetch'));
In this example $alfred is a brown dog and $lassie is a golden dog. The two instances are separate from each other, the only thing they have in common is that they both have a property called $color.
If you want a variable that is available in all Dogs for example, you need a class variable:
class Dog{
public $color;
public static $numberOfLegs; //Class variable available in every instance of Dog.
public function __construct($color, $numberOfLegs){
$this->color = $color;
self::$numberOfLegs = $numberOfLegs;
}
}
class TrainedDog extends Dog{
public $tricks;
public function __construct($color, $tricks){
$this->tricks = $tricks;
parent::__construct($color);
echo parent::$numberOfLegs;
}
}
This does not make much sense in many cases though, because if you have two instances of the parent class (in you're case Core), they also share the class variable.
Unless you can ensure that Core is instanciated only once, this approach will not work. If it does only exist once, you can just as well use constant variables to store the 2 properties.
If there exist multiple instances/objects of Core, I'd recommend using a composition (as suggested by Alvin Wong).
class Core{
//Just as you programmed it.
}
class Property{
private $core;
public function __construct($core){
$this->core = $core;
echo $core->curPath;
}
}
Try this
include_once('core.php');
$core = new Core('test', 'path');
$core->loadController('property');
class Property extends Core
{
function __construct($date)
{
print $date->curpath;
}
}
class Core
{
public $uri;
public $curpath;
function __construct($uri, $curpath)
{
$this->uri = $uri;
$this->curpath = $curpath;
}
// Load the controller based on the URL
function loadController($name)
{
//Instantiate the controller
require_once($name.'.php');
$controller = new $name($this);
}
}
As it is right now, i have my class system to be embedded in my core class. So i call my classes as such:
$cms->userClass->function();
But this means that for every function i have in my userClass, i constantly need to add:
global $cms;
To be able to access the database class as such:
$cms->db->function();
Is there any way to set a global for the whole class, instead of having to define it at the start of every function?
Instead of using functions everywhere, if you build your own classes and put those functions within the classes you could set a single property within the class and access everything by $this->var....
$class = new MyClass($cms);
echo $class->cms; //doesn't work cause it's private
class MyClass () {
private $cms; //private so it's only accessible within this class
function __construct ($cms) {
$this->cms = $cms;
}
//all your functions here can use $this->cms
function myFunction () {
echo $this->cms->func(); //this will work
}
}
I don't think there is global for a class.
However, a couple of alternatives:
have a reference to the global $cms variable in a class, so:
private $cmsref;
function __construct(){
global $cms;
$this->cmsref = &$cms; // $this->cmsref will be a reference to $cms now
}
use the superglobal $_GLOBALS:
function foo(){
// to access $cms:
$_GLOBALS["cms"];
}