I think my question is kind of noobish but i can't figure out how this stuff is working with PHP. It is a autoloaded class and I want to use my logging class for it.
I know I could have $log also as instance variable but I want it like that.
namespace Bal\Blub;
$log = new Logger('activities');
$log->pushHandler(new StreamHandler(__DIR__.'/../../log/activties.log', Logger::DEBUG));
$log->debug("is working here");
class Foo {
public function bar() {
global $log;
$log->debug("this is my message");
}
}
I don't understand why $log has no value in that case...
Edit: Of course I meant global and not public.
Ok so thanks for your code-style advises. I am quite aware that globals are bad practice. Though it was not my question. The answer for it is to use the global also in the namespace scope, which makes sense, but is a little strange if you are used to the PHP scripting approach.
namespace Bal\Blub;
global $log;
$log = new Logger('activities');
$log->pushHandler(new StreamHandler(__DIR__.'/../../log/activties.log', Logger::DEBUG));
$log->debug("is working here");
class Foo {
public function bar() {
global $log;
$log->debug("this is my message");
}
}
it is global $log. not public $log.
but be careful. globals are always evil. if you really need globals, use at least static variables.
<?php
class Globalholder{
public static $log;
}
Globalholder::$log = new Logger(...);
function foo(){
$log = Globalholder::$log;
$log->logsomething("Hello World");
}
global keyword, a static class property acting like a global variable, a singleton class...all can work, but since we're at it, why not trying to avoid bad practices and use DI?
Right now, your Foo class is tightly coupled with the Logger class, and that can make maintaince hard whenever, some day, you're going to change all the reference to the Logger class.
Why not something simpler like:
class Foo
protected $logger;
public function __construct(Logger $logger)
{
$this->logger = $logger;
}
public function bar($string)
{
$this->logger->debug($string);
}
}
$log = new Logger('activities');
$foo = new Foo($log);
$foo->bar("test");
This way you're decoupling (I know this code can be made even better) the two classes, and you're also making the code easy testable by passing a mock Logger object.
Related
So I have something like this:
class SomeClass{
//do some stuff
}
$variable = new SomeClass();
Now that in a php file called SomeClass.php for example, I want to in some other class called OtherClass.php do something like:
class OtherClass{
function doSomething(){
$variable->call_some_method();
}
}
How would I achieve this? I have thought of global variables, but then I see frameworks like Zend doing stuff like: $this->view->what_i_want_to_pass_to_the_view = 'hello apple sauce';
So what's a good way to do, essentially what I want to do.
Note: Some people are assuming I want to do global variables, this is not true. I am trying to replicate how Zend does something like $this->view in a class to send something to the view and then in the view, calls $this->view to get what was sent. I assumed this was done through globals...
This concept is called "Dependency injection" and is considered to be a best practice for doing even that.
class SomeClass{
//do some stuff
}
$some = new SomeClass();
class OtherClass{
function doSomething(SomeClass $some){
$some->call_some_method();
}
}
$otherclass = new OtherClass();
$otherclass->doSomething($some);
Alternatively, you can just inject the dependency on constructing time:
class OtherClass{
private $some = null;
function __construct(SomeClass $some){
$this->some = $some;
}
function doSomething(){
$this->some->call_some_method();
}
}
Depends on what you want to achieve and how often you need the dependency.
First, I’d like to congratulate you on finding a way to introduce global variables to Zend Framework as it breaks everything Zend Framework is about (OOP, MVC architecture etc).
Secondly, it’s bad practice. It’s possible, but bad too. If you find you’re struggling to do something with the language, then chances are there’s an easier way accomplish what you’re trying to do.
Although this isn’t an answer, I’d implore you to divulge more into your problem and why you’re wanting to use a class instance, globally-defined, in another class rather than an abstract example. Chances are, we can then help you become a better programmer by offering an alternative approach rather than instilling bad practices for you to go about building your websites and web applications.
I believe what you need is 'extends' i'll give you an example.
class Hello {
public function world() {
echo 'Hello World!';
}
}
class someClass extends Hello {
public function doSomething() {
$this->world();
}
}
$obj = new someClass();
$obj->doSomething();
There are a few ways of doing it:
1) Extend SomeClass
class OtherClass extends SomeClass
{
function doSomething(){
$this->call_some_someclass_method();
}
}
2) Pass the SomeClass instance into the OtherClass (not good coding practice)
$a = new SomeClass();
$b = new OtherClass();
$b->someInstance($a);
class OtherClass extends SomeClass
{
function someInstance($someClass){
$this->someClass = $someClass;
}
function doSomething(){
$this->someClass->call_some_method();
}
}
3) Create an instance inside OtherClass
class OtherClass extends SomeClass
{
function someInstance(){
$this->someClass = new SomeClass;
}
function doSomething(){
$this->someInstance();
$this->someClass->call_some_method();
}
}
Let's say I have the following class:
class SQLMapper{
static find_user_by_id($id){
//sql logic here, using the $_DATABASE global to make a connection
}
}
I could simply call:
global $_DATABASE;
at the top of my function, but I don't want to do that for ALL of my static methods. Is there a way to get a static variable inside my class to reference the global $_DATABASE array?
EDIT: I can't assign it in the constructor, since this is all static, and the constructor is never called.
You can use the super-global array $_GLOBALS to access your $_DATABASE variable. For example:
query( $GLOBALS['_DATABASE'], 'some query' );
Alternatively, write a static function that returns the contents of that variable:
class SQLMapper
{
static function getDatabase()
{
global $_DATABASE;
return $_DATABASE;
}
static function find_user_by_id($id)
{
query( self::getDatabase(), 'some query' );
}
}
If it hurts, its likely that you're
doing it wrong.
First off, without seeing more of your code its impossible to provide a more concrete solution, but I would strongly recommend that you consider rearranging your class structure so that your static functions (it sounds like you've got a long list of them to implement) become non-static.
In essence, you should consider accessing an instantiated instance of SQLMapper and then calling the appropriate method from the instance. Using this paradigm, you could just instantiate a class level property for $_DATABASE which can then be freely referenced by all methods in the class.
For example:
class SQLMapper {
private $_db;
public function __construct()
{
global $_DATABASE;
$this->_db = $_DATABASE;
}
public function find_user_by_id($id) {
$sql = "Select * from User WHERE Id = ?";
$stmt = $this->_db->prepare($sql, $id);
return $stmt->execute();
}
}
With that said, using globals is generally a sign of poor code quality so I would also suggest that you consider taking a more object-oriented approach to your current design and look for tried and true methods for eliminating globals from your application altogether.
I'm not so sure I understand what you mean, sorry, but can you try using the static keyword?
Hi i have a little collection of classes some of which should be globally accessible.
I found something similar in Zend_Registry, but reading its code i cant understand how a call to a static function could return an initialized instance of a class...
i need to do something like:
<?php
//index.php
$obj = new myUsefulObject();
$obj->loadCfg("myFile.xml");
$req = new HTTPRequest();
$req->filter("blablabla");
myappp::registerClass("object",$obj);
myappp::registerClass("request",$req);
$c = new Controller();
$c->execute();
?>
Here i have filtered the Request object and i want the controller to be able to reach that already filtered request.
<?php
class Controller
{
function __construct()
{
$this->request = Application::getResource("request");//This must be the filtered var =(
}
}
?>
I don't know how to implement that Application::getResource(), the only thing i know is that it must be a static method because it can't be related to a specific instance.
Aside from static methods, PHP also has static properties: properties that are local to the class. This can be used to implement singletons, or indeed a Registry:
class Registry {
private static $_registry;
public static function registerResource($key, $object)
{
self::$_registry[$key] = $object;
}
public static function getResource($key) {
if(!isset(self::$_registry[$key]))
throw InvalidArgumentException("Key $key is not available in the registry");
return self::$_registry[$key];
}
}
1: You can acess global variables with the global keyword:
$myVar = new SomethingProvider();
class MyClass {
public function __construct() {
global $myVar;
$myVar->doSomething();
}
}
2: You can do the same using the $GLOBALS super-global:
$myVar = new SomethingProvider();
class MyClass {
public function __construct() {
$GLOBALS['myVar']->doSomething();
}
}
3: You can define a singleton class (the wikipedia has a nice example, too).
4: You could add globals as public static members (or private static members with public getters/setters) to a class:
class Constants {
const NUM_RETIES = 3;
}
if ($tries > Constants::NUM_RETRIES) {
# User failed password check too often.
}
class Globals {
public static $currentUser;
}
Globals::$currentUser = new User($userId);
I wouldn't recommend the first two methods, overwriting the values of these global variables unintentionally is too easy.
Seems to me like you might need some form of Singleton design pattern;
Check this out!
Hope it helps!
I have a variable on the global scope that is named ${SYSTEM}, where SYSTEM is a defined constant. I've got a lot of classes with functions that need to have access to this variable and I'm finding it annoying declaring global ${SYSTEM}; every single time.
I tried declaring a class variable: public ${SYSTEM} = $GLOBALS[SYSTEM]; but this results in a syntax error which is weird because I have another class that declares class variables in this manner and seems to work fine. The only thing I can think of is that the constant isn't being recognised.
I have managed to pull this off with a constructor but I'm looking for a simpler solution before resorting to that.
EDIT
The global ${SYSTEM} variable is an array with a lot of other child arrays in it. Unfortunately there doesn't seem to be a way to get around using a constructor...
Ok, hopefully I've got the gist of what you're trying to achieve
<?php
// the global array you want to access
$GLOBALS['uname'] = array('kernel-name' => 'Linux', 'kernel-release' => '2.6.27-11-generic', 'machine' => 'i686');
// the defined constant used to reference the global var
define(_SYSTEM_, 'uname');
class Foo {
// a method where you'd liked to access the global var
public function bar() {
print_r($this->{_SYSTEM_});
}
// the magic happens here using php5 overloading
public function __get($d) {
return $GLOBALS[$d];
}
}
$foo = new Foo;
$foo->bar();
?>
This is how I access things globally without global.
class exampleGetInstance
{
private static $instance;
public $value1;
public $value2;
private function initialize()
{
$this->value1 = 'test value';
$this->value2 = 'test value2';
}
public function getInstance()
{
if (!isset(self::$instance))
{
$class = __CLASS__;
self::$instance = new $class();
self::$instance->initialize();
}
return self::$instance;
}
}
$myInstance = exampleGetInstance::getInstance();
echo $myInstance->value1;
$myInstance is now a reference to the instance of exampleGetInstance class.
Fixed formatting
You could use a constructor like this:
class Myclass {
public $classvar;
function Myclass() {
$this->classvar = $GLOBALS[SYSTEM];
}
}
EDIT: Thanks for pointing out the typo, Peter!
This works for array too. If assignment is not desired, taking the reference also works:
$this->classvar =& $GLOBALS[SYSTEM];
EDIT2: The following code was used to test this method and it worked on my system:
<?php
define('MYCONST', 'varname');
$varname = array("This is varname", "and array?");
class Myclass {
public $classvar;
function Myclass() {
$this->classvar =& $GLOBALS[MYCONST];
}
function printvar() {
echo $this->classvar[0];
echo $this->classvar[1];
}
};
$myobj = new Myclass;
$myobj->printvar();
?>
The direct specification of member variables can not contain any references to other variables (class {public $membervar = $outsidevar;} is invalid as well). Use a constructor instead.
However, as you are dealing with a constant, why don't you use php's constant or class constant facilities?
You're trying to do something really out-of-the-ordinary here, so you can expect it to be awkward. Working with globals is never pleasant, especially not with your dynamic name selection using SYSTEM constant. Personally I'd recommend you use $GLOBALS[SYSTEM] everywhere instead, or ...
$sys = $GLOBALS[SYSTEM];
... if you're going to use it alot.
You could also try the singleton pattern, although to some degree it is frowned upon in OOP circles, it is commonly referred to as the global variable of classes.
<?php
class Singleton {
// object instance
private static $instance;
// The protected construct prevents instantiating the class externally. The construct can be
// empty, or it can contain additional instructions...
protected function __construct() {
...
}
// The clone and wakeup methods prevents external instantiation of copies of the Singleton class,
// thus eliminating the possibility of duplicate objects. The methods can be empty, or
// can contain additional code (most probably generating error messages in response
// to attempts to call).
public function __clone() {
trigger_error('Clone is not allowed.', E_USER_ERROR);
}
public function __wakeup() {
trigger_error('Deserializing is not allowed.', E_USER_ERROR);
}
//This method must be static, and must return an instance of the object if the object
//does not already exist.
public static function getInstance() {
if (!self::$instance instanceof self) {
self::$instance = new self;
}
return self::$instance;
}
//One or more public methods that grant access to the Singleton object, and its private
//methods and properties via accessor methods.
public function GetSystemVar() {
...
}
}
//usage
Singleton::getInstance()->GetSystemVar();
?>
This example is slightly modified from wikipedia, but you can get the idea. Try googling the singleton pattern for more information
I'd say the first two things that stand out to me are:
You don't need the brackets around the variable name, you can simply do public $system or public $SYSTEM.
While PHP may not always require it it is standard practice to encapsulate non-numeric array indexes in single or double quotes in case the string you're using becomes a constant at some point.
This should be what you're looking for
class SomeClass {
public $system = $GLOBALS['system'];
}
You can also use class constants which would instead be
class SomeClass {
const SYSTEM = $GLOBALS['system'];
}
This can be referenced within the class with 'self::SYSTEM' and externally with 'SomeClass::SYSTEM'.
Suppose I have the following code:
class siteMS
{
...
function __CONSTRUCT()
{
require 'config.php';
$this->config = new siteMSConfig;
...
}
...
}
From inside the siteMSConfig class can I determine weather or not it is being called from inside the siteMS class?
Yes, but there's no "pretty" way to do it - you'll end up looking through a backtrace or something similar.
It would be better to pass an (optional?) parameter to the siteMSConfig constructor like this:
class siteMSConfig
{
public function __construct($inSiteMS = false)
{
}
}
or alternatively, subclass siteMSConfig:
class siteMSsiteMSConfig extends siteMSConfig
{
public function __construct()
{
// Possibly call parent::__construct();
}
}
Technically yes, you could use debug_backtrace to figure out who your caller was.
Writing a class which alters its behaviour based purely on where it called from is asking for a world of pain later on though. Why not parameterise the different behaviour, or make a subclass?
I guess you have to pass it with variable, from what place you called it
$this->config = new siteMSConfig ('siteMS');