I'm currently working on a project where I have to work with huge arrays. With huge, I mean 1k elements or more. Since these are a lot of arrays and i sometimes mess things up, I decided to create a class with static functions so i can call the functions which would make the entire project easier to read. This is what I currently have:
ArrayAccess.class.php:
require "dep/arrays/elements.php";
class ArrayAccess {
public static function get_value_from_element($element) {
return $elements[$element];
}
}
elements.php:
<?php
$elements = array(
"sam" => 6, ... and so on ...
I simply want to be able to use ArrayAccess::get_value_from_element($element) in my project. It is so much easier to read than all these indexes everywhere. However, the array is defined in the elements.php file - I can't use that in the class.
So how can I access the array in my class? Please note, I cannot copy it into the class, the file would be larger than 400k lines, this is not an option.
You can return a value from an include (or require in this case) and store that to a static property the first time the function is called.
elements.php:
<?php
return array("sam" => 6, ...);
DataAccess.php:
class DataAccess {
private static $elements = array();
public static function get_value_from_element($element) {
if(self::$elements === array()) {
self::$elements = require "elements.php";
}
return self::$elements[$element];
}
}
You should also avoid naming your class ArrayAccess, since it already exists in PHP.
In elements.php
<?php
return array( // use return so you can retrieve these into a variable
"sam" => 6, ... and so on ...
Then in the class
<?php
class ArrayAccess {
public static $elements = null; // set up a static var to avoid load this big array multiple times
public static function get_value_from_element($element) {
if(self::$elements === null) { // check if null to load it from the file
self::$elements = require('elements.php');
}
return self::$elements[$element]; // there you go
}
}
If you don't want do the if statement in the getter every time, you should probably find some where else to load the file into the static variable before using the getter.
An alternative is to declare $elements as global in your class:
require "dep/arrays/elements.php";
class ArrayAccess {
public static function get_value_from_element($element) {
global $elements;
return $elements[$element];
}
}
Related
I'm looking for more comfortable/more short version of Switch() statement in case of using multiple functions.
I'll give you one example: imagine 100-200 functions in one class, and you want to call only one of them by setting value to id in that class.
In my particular case, I have the following structure of PHP file:
<?php
class _main
{
function request($id)
{
switch($id)
{
case 0:
$this->writeA();
break;
case 1:
$this->writeB();
break;
///...
// then we have 100-200 functions like this in switch.
}
}
function writeA()
{
echo('a');
}
function writeB()
{
echo('b');
}
}
$id = 1;
$x = new _main();
$x->request($id);
?>
For some of you it may seem weird, but I don't want to have that much lines of code with case and break. For me, they are just making code more difficult to read.
(by the way, writing it 100 times will not making it fun for me too).
CONCLUSION
What could be the best,fast and comfortable method?
Can I store functions to array and then call them?
And will it affect performance? Will be Swicth() even faster?
Thank you :)
EDIT
Perhaps there is a different way of thinking/coding and not only array/switch thing.
I can't say I would ever recommend this but if you really want that many methods within a single class and a singular function to route the calls through...
<?php
class MyClass
{
public $id;
public function callFunction()
{
$funcName = 'execute' . $this->id;
return $this->$funcName();
}
private function execute1()
{
echo 'execute1() Called.';
}
private function execute2()
{
echo 'execute2() Called.';
}
}
$c = new MyClass();
$c->id = 1;
$c->callFunction();
Output:
execute1() Called.
I feel like there is most likely another way to approach this with more information utilising Interfaces and Abstract classes, but with the information to go off the above might suffice your requirement.
Edit: Sadly I don't have the time right now to come up with a detailed solution, and I don't really have enough information to go off but perhaps utilising interfaces is your best solution for your requirement. Below is a very quick example.
<?php
interface WritableInterface
{
public function write($data);
}
class VersionOneWriter implements WritableInterface
{
public function write($data)
{
return $data . '<br/>';
}
}
class VersionTwoWriter implements WritableInterface
{
public function write($data)
{
return $data . $data . '<br/>';
}
}
class MyMainClass
{
public function request(WritableInterface $writer, $data)
{
return $writer->write($data);
}
}
$c = new MyMainClass();
$w1 = new VersionOneWriter();
$w2 = new VersionTwoWriter();
echo $c->request($w1, 'DataString');
echo $c->request($w2, 'DataString');
Essentially when you call your request function you pass along a Writer class which implements the WritableInterface. Anything that implements that interface has to have a write() method.
Now when you pass your data across with your method, since you are also passing a writer along that can handle the data you can safely call ->write($data) within your request() method and the result will be dependent on the class you passed through.
If you ever need another method of writing you can just add create another class that implements your interface
Hopefully that made some sense, it was a bit of a ramble as I have to disappear for a bit. If you have any questions I'll try to check back when I have time.
--
Edit2:
The define() in this instance requires PHP7+ since I'm defining an array, but you could prior to PHP7 you could just use a standard array. $classMap = ['FirstClass', 'SecondClass'];
interface MyInterface {}
class FirstClass implements MyInterface {}
class SecondClass implements MyInterface {}
$requestParam = 1;
define('CLASS_MAP', array(
'FirstClass',
'SecondClass',
));
$classMap = CLASS_MAP[$requestParam]; // SecondClass
$class = new $classMap;
var_dump($class); // Dumps out: object(SecondClass)#1 (0) {}
In the progress of writing a little framework for a web app I came along some difficulties in making classes communicate with each other.
Environment
I have an abstract class called LizardModule, that should be extended by all the single modules of the web-app. This class has a final protected function registerController(...), that creates a new Object of the type LizardController. This is, as it sounds, based on the idea of MVC. With the final protected function registerFunction(...), modules can register functions for every controller. Those are stored using addFunction(...) on the controller object. Here is what this looks like:
Example Module:
class ModuleOverview extends LizardModule {
protected function setup() {
$this->registerController(
'overview',
'App Overview'
);
$this->registerFunction(
'overview',
'myfunction',
'My Function',
array(&$this, 'theFunctionToCall')
);
}
public function theFunctionToCall() { ... Generate Content ... }
}
Module Class:
class LizardModule {
private $controllers = array();
final public function __construct() { $this->setup(); }
abstract protected function setup();
[...]
final protected function registerController($controllerSlug, $controllerName) {
if (array_key_exists($controllerSlug, $this->controllers))
return false;
$this->controllers[$controllerSlug] = new LizardController($controllerSlug, $controllerName);
}
final protected function registerFunction($controllerSlug, $functionSlug, $functionName, callable $function) {
if (!array_key_exists($controllerSlug, $this->controllers))
return false;
$this->controllers[$controllerSlug]->addFunction($functionSlug, $functionName, $function);
}
}
This results in a lot of objects of type LizardController in different places of the app. To make all of those objects accessable, I created a singleton class LizardRouter, that should hold a reference to all of those controller objects. Therefore, the controller-object registers itself with this singleton class:
Controller Class:
class LizardController {
[...]
private $functions = array();
public function __construct($slug, $name, $menu) {
$this->slug = $slug;
$this->name = $name;
$this->menu = $menu;
LizardRouter::registerController($this);
}
public function addFunction(...) { Tested, this works. }
public function getFunctions() {
return $this->functions;
}
}
Router Class:
final class LizardRouter {
[...]
public static function getControllers() {
return static::getInstance()->controllers;
}
public static function registerController(LizardController $controller) {
static::getInstance()->controllers[] = $controller;
}
}
The Problem
The whole thing works alright for the controllers. In my interface class, I can read out all controllers and print a menu containing their names. The problem is: Whenever I access the controllers functions-array (see controller class) through the controllers-array given by the routing class, I get an empty array. I asume that somewhere a reference is not working and I am passing the actual controller object, before my module-class was able to add the functions to the controllers functions-array. But I can't figure out where exactly the problem lies. Here is an example from my interface class showing the problem:
foreach (LizardRouter::getControllers() as $controller) {
// Allways returns an empty array, even though
// the module added functions to the controller.
$controller->getFunctions();
}
Since this is a very specific case, I guess it is unlikely, that anyone will ever stumble upon the same problem. Anyway; I found the reason for the problem:
Objects are by default passed as reference since PHP5. Variables are by default passed by value.
Arrays are handled like variables, so when I pass an array containing object-references, a new copy of this array is created and passed. Object references added to the array after it was passed are therefore only added to the original array.
The solution i chose was to create my own "array-class" for holding objects. It has nothing more than a private array object, a setter and a getter. Since this custom array class is an object, it is automatically passed by reference. Later I also added some functions to conveniently access the array - a good side-effect.
I am trying to add functions to class from a separate file, I wonder if this could be possible!
$mClass = new MyClass();
$mClass->new_Functions[0](10); // Is there a way to have it in this form?
class myClass
{
private $Pvar = 5;
$new_Fcuntions;
function __construct()
{
include('additional.functions.php');
$arr = get_defined_functions();
$this->new_Functions = $arr['user'];
// trying to call the function with parameter 10
call_user_func(array($this, $this->new_Functions[0]), 10);
}
}
[additional.functions.php] file
function operate($y)
{
return $this->Pvar * $y;
}
----- Edited ------- as it wasn't clear!
"additional.functions.php" is a module and there will be multiple modules to be added to the application, and every module could have more than single function and modules could call one another!
additional.functions.php [module file]
function operate($y)
{
return $this->Pvar * $y;
}
function do-more($foo)
{
return $this->operate(20) + $foo;
}
another.functions.php [another module]
function do-another($foo)
{
return $this->do-more(30) - $foo;
}
function add($foo, $bar)
{
return $foo + $bar;
}
appreciate every participation, its been a while since I am trying to maneuver around with it!
Is this possible or should I give up!
It looks to me like you are looking for Traits, which are a new feature as of PHP 5.4.0. Using traits, you can have snippets of code "mixed in" to other classes, a concept known as "horizontal reuse".
If you are not looking for traits, it's possible that you could do what you wanted with Runkit, however I would suggest staying as far away from it as possible, if you are not genuinely interested in PHP internals as well.
In any event, whatever you are trying to do is very interesting
I got it to work with dependency injection. The pvar has to be public or create a __get method to return the private variable. I also used the function name because it seems cleaner to me to use it via name rather than it's position in the list but if you want to keep that then just put $key where you see $value from the line: $this->function_list[$value] = ...
function operate($y, $that)
{
return $that->Pvar * $y;
}
class Example {
public $function_list = array();
private $Pvar = 5;
public function __construct()
{
$list = get_defined_functions();
$that = $this;
foreach ($list['user'] as $key => $value) {
$this->function_list[$value] = function() use ($value, $that) {
print call_user_func_array($value, array_merge(func_get_args(), array($that )));
};
}
}
public function __get($key)
{
if (isSet($this->$key)) {
return $this->$key;
} else {
throw new \Exception('Key "'.$key.'" does not exist');
}
}
}
$Ex = new Example();
$Ex->function_list['operate'](10);
If you want to extend MyClass from your modules (and not to initialize it, like in your example code), than you could do it in a way like this:
<?php
namespace modules\MyModuleA;
class MyClassExtension
{
private $MyObject;
public function __construct(\MyClass $MyObject)
{
$this->MyObject = $MyObject;
}
public function doSomething($anyParameter)
{
return $this->MyObject->doSomethingElse($anyParameter * 5, 42, 'foo');
}
}
And MyClass:
<?php
class MyClass extends \Extensible
{
// some code
}
abstract class Extensible
{
private $extensions = [];
public function extend($extension)
{
$this->extensions[] = $extension;
}
public function __call($methodName, $parameters)
{
foreach ($this->extensions as $Extension) {
if (in_array($methodName, get_class_methods($Extension))
return call_user_func_array([$Extension, $methodName], $parameters);
}
throw new \Exception('Call to undefined method ' . $methodName . '...');
}
public function hasExtension($extensionName)
{
return in_array($this->extensions, $extensionName);
}
}
And put it all together:
<?php
$moduleNames = ['MyModuleA', 'MyModuleB'];
$MyObject = new \MyClass;
foreach ($moduleNames as $moduleName) {
$className = '\\modules\\' . $moduleName . '\\MyClassExtension';
$module = new $className($MyObject);
$MyObject->extend($module);
}
// Now you can call a method, that has been added by MyModuleA:
$MyObject->doSomething(10);
You should add an interface for the extension classes of course...
The problem is: What happens if any code in your application calls a method of $MyObject, that is not there, because the module has not been loaded. You would always have to check if ($MyObject->hasExtension('ModuleA')) { ... }, but, of course, the application shouldn't be aware of any module. So I would not design an application in such a way.
I would suggest to use traits (mix-ins). See PHP reference
If you can have another class in that file instead of file with functions
- the best solution will be Traits
http://php.net/manual/en/language.oop5.traits.php
or using inheritance
If you move that code to class you can avoid a lot of unnecessary code. I mean:
include('additional.functions.php');
$arr = get_defined_functions();
$this->new_Functions = $arr['user'];
// trying to call the function with parameter 10
call_user_func(array($this, $this->new_Functions[0]), 10);
It'll be e.g.:
class myClass extends MyBaseClassWithMyAwesomeFunctions
{
private $Pvar = 5;
}
Maybe this approach helps you:
In the files with the additional functions, don't define named functions, but return a closure, that expects (at least) the object (instance of MyClass) as parameter:
<?php
// additional.functions.php
return function ($myObject) {
$Object->multiplyPvar($myObject->getTheNumber());
$Object->doSomethingElse(42, 'foo');
};
The client, that builds MyClass collects those functions from the files into the array:
<?php
$files = [
'/path/to/my/additional.functions1.php',
'/path/to/my/additional.functions2.php'
];
$initFunctions = [];
foreach ($files as $path)
$initFunctions[] = include $path;
$MyObject = new \MyClass($initFunctions);
The constructor then calls those functions:
<?php
class MyClass
{
public function __construct(array $additionalInitFunctions)
{
foreach ($additionalInitFunctions as $additionalInitFunction)
$additionalInitializerFunction($this); // you can also add parameters of course
}
}
This way the class keeps very well testable as well as the function files. Maybe this could help you in any way. You should never ever think about modifying the internal (private) state of an object directly from any code from outside of the class. This is not testable! Think about writing tests before you implement your code (called "test driven development"). You will see, it is not possible to test a class, if you allow any code outside of that class to modify the internal (private) state of the class instance. And you don't want to have this. If you change some internal implementation detail in your class without breaking the unit test of that class, you will anyways probably break some code in any of your additional.functions.php files and no test will tell you: "Hey: you've broken something right now".
I'm struggling to find a correct approach to pass data between classes, which do not directly call each other, and are only related through a parent class (which I now use, but I consider it a dirty workaround rather than anything near a solution).
I have 3 classes both able to read input and write output, and based on configuration I set one to read, another one to write. It may even be the same class, they all share a parent class, but they are always two separate instances called from a controller class.
Currently I use this sort of functionality:
class daddy {
public static $data;
}
class son extends daddy {
public function setData() {
parent::$data = "candy";
}
}
class daughter extends daddy {
public function getData() {
echo parent::$data;
}
}
while($processALineFromConfig)
$son = new son;
$son->setData();
$daughter = new daughter;
$daughter->getData();
daddy::$data = null; //reset the data, in the actual code $daughter does that in parent::
}
Instantination of these classes runs in a loop, therefore I always need to reset the data after $daughter receives them, 'cos otherwise it would stay there for another pass through the loop.
I'm absolutely sure it's not how class inheritance is supposed to be used, however I'm struggling to find a real solution. It only makes sense the data should be stored in the controller which calls these classes, not the parent, but I already use return values in the setter and getter functions, and I am not passing a variable by reference to store it there to these functions 'cos I have optional parameters there and I'm trying to keep the code clean.
What would be the correct approach to pass data through the controller then?
Thanks!
The best option would be for two object share some other, third object. This would be the class for "third object" which will ensure the exchage:
class Messenger
{
private $data;
public function store($value)
{
$this->data = $value;
}
public function fetch()
{
return $this->data;
}
}
Then a class for both instance, that will need to share some state:
class FooBar
{
private $messenger;
private $name = 'Nobody';
public function __construct($messenger, $name)
{
$this->messenger = messenger;
$this->name = $name;
}
public function setSharedParam($value)
{
$this->messenger->store($value);
}
public function getSharedParameter()
{
return $this->name . ': ' . $this->messenger->fetch();
}
}
You utilize the classes like this:
$conduit = new Messenger;
$john = new FooBar($conduit, 'Crichton');
$dominar = new FooBar($conduit, 'Rygel');
$dominar->setSharedParameter('crackers');
echo $john->getSharedParameter();
// Crichton: crackers
Basically, they both are accessing the same object. This also can be further expanded by making both instance to observe the instance of Messenger.
What is the best way to make a variable accessable to all classes.
For example, I want to have a configuration file (Call it config.php) that is going to have a variable like so:
$server_url = "www.myaddress.com";
And I have a main library type file that contains a bunch of classes that need to access the $server_url. So here begins that main library file:
require 'config.php';
class one {
function a() {
$html = "<a href='$server_url/main.php'>LINK</a>"
return $html;
}
function b() {
$html = "<a href='$server_url/about.php'>LINK</a>"
return $html;
}
}
class two {
function new() {
$html = "<a href='$server_url/blah.php'>LINK</a>
}
}
What would be the best way to make $server_url from the config.php available to every function? Or at least available to all the functions in a class?
Personally I would use a static entity to hold all configuration values.
Usually, most php applications have a single entry point (index.php) that can load up the config.php file and make the static entity available from that point.
If your application has multiple entry points, then you will need to include config.php in each of these points.
Something like this:
<?php
class Configurator{
private static $_configuration = array();
public static function write($key, $value) {
self::$_configuration[$key] = $value;
}
public static function read($key) {
return self::$_configuration[$key];
}
}
Configurator::write('server', 'http://localhost');
Configurator::read('server');
?>
CakePHP has a similar class: http://api.cakephp.org/view_source/configure/
Make the config into a class in itself and use a static methods either along the line of serverUrl() or get('server_url'). Then call them like any other static methods to classes (I'll choose the latter in this example):
$html = "<a href='" . Config::get ('server_url') . "/main.php'>LINK</a>";
The config class could be pretty slim, use a constructor like:
public function __construct (array $config)
{
foreach ($config as $key => $value)
{
$this->$key = $value;
}
}
And add the get() method along these lines:
public function get ($key)
{
return $this->$key;
}
This way you can read the config from an array that you can have as a separate, actual config file, and reuse the same code for multiple projects.
You'll also be able to access the variables from anywhere in the project and you'll get a sort of pseudo-namespacing (in case the project needs to run on an older version of PHP).
Please, don't copy the code verbatim, it's written as an example.
think of globals are evil. Try to use design patterns to get access to some configs globally.
I'm a big fan of singletons to get global access to objects, arrays or other data-types.
<?php
class st {
static $_this;
function __construct(){
self::$_this = $this;
}
static function &getInstance(){
return self::$_this
}
static function set($key, $value){
self::$_this[$key] = $value;
}
static function &get($key){
return self::$_this[$key];
}
}
// Usage
new st();
st::set('foo', 'bar');
// In some class
st::get('foo'); //return 'bar'
// Or when there are some classes/objects
st::getInstance()->foo->bar();
$st =& st::getInstance();
$st->foo->bar();
?>
Roughly wrote down a small singleton, but don't know whether there is a syntax error.
While handling with getInstance it's certain that you define the variable by reference =&
Define a constant in config.php like:
define('SERVER_URL', '...');
In your class:
echo SERVER_URL;
What works for me the best is to use a config file like config.ini
And then to use $my_config = parse_ini_file(file path/config.ini');
Now everywhere in my code including inside functions and classes, I will use
The PHP superglobal like this:
$GLOBALS["my_config"]['my_global_var']