Unable to access variable from base .php called by required php - php

assume i have a code as below:
index.php
<?php
require 'file_1.php';
// file_1.php contents can go here, but i'm trying to make this simple and clutter free, thus clean.
// The reason being to not centralize all code in a single file should file_2.php, file_3.php, file_n.php exist.
$app = new type_of_object();
$app->intialize_some_stuff();
?>
file_1.php
<?php
$app->access_some_method($param1, new function($app) {
// do some logic here...
});
?>
doing this approach, i get an error such as below:
Notice: Undefined variable: app in X:\project_folder\file_1.php on line 2
to summarize, i'm trying to decentralize all codes from being defined in index.php and instead, have them hosted by different files such as file_1.php to file_n.php. The problem is, i'd be needing to access the $app variable from index.php on the required files such as file_1.php to file_n.php since i'll only need 1 instance of this, no duplicates allowed.
i'm also open to being taught another approach on this.
cheers!
EDIT: its worth nothing that i'm fairly new in PHP, and that i've already done few research. except that what i'm getting is the opposite of my issue. also, the need to access $app of index.php from other php files is the very center of my question.

Splitting code can be a good idea to achieve a better maintainability. You should avoid unclear scripts name.
at a high degree, you want definitely go on composer approach to maintain packages.
Anyway, for a basic code splitting, the rules are the same than a regular script. Code is interpreted at the time it is read. Just rewrite your example in one script :
<?php
$app->access_some_method($param1, new function($app) {
// do some logic here...
});
$app = new type_of_object();
$app->intialize_some_stuff();
?>
See the problem ? $app is simply not initialized when calling the access_some_method.
So, this will work :
<?php
$app = new type_of_object();
$app->intialize_some_stuff();
require 'file_1.php';
?>
But the gain is poor. If you already have a class, there's a few cases where it can be interesting to split logic among many files. I think this one is a better example (all files in the same folder, no namespaces) :
<?php
require('App');
require('AppRequest');
$app = new App();
$request = new AppRequest();
$app->process($request);
With this way, you can split the main app logic and the request analysis logic for instance

Related

Include generic testcase in codeception

I have multiple similar websites that I want to test. Here's the current approach:
Clone an existing codeception project
Adjust the variables
Add some additional specific test cases if required
This works just fine, but has one issue. If the general test case changes that means that I have to go into every project and make the changes. So what I would rather see is a way to include a generic top level test case in every project and call it with a parameter.
I tried so with a simple include() statement, but unfortunately this doesn work. And ideas how I can accomplish this?
Here some code of my initial try:
/home/tests/site1/tests/acceptance/isOnlineCept.php
include("../1generic_tests/isonline.php");
$I = new AcceptanceTester($scenario);
$I->am('user');
$I->wantTo('see the content of the site');
$I->lookForwardTo('see the homepage');
$I->amOnPage('/');
$I->see("Tech, Geek and Rock'n'Roll");
The file I include looks like this
$I = new AcceptanceTester($scenario);
$I->am('user');
$I->wantTo('see the content of the site');
$I->lookForwardTo('see the homepage');
$I->amOnPage('/');
$I->see('something else');
Unfortunately it fails with this error
[PHPUnit_Framework_Exception] Undefined index: class
Maybe include is not the right way to do it, but what would be a better way?
You can use Page Object for this.
Create one Constants.php file using Page Object where you can define all the selectors.
Create one other file where you can keep all common operation going to be performed. E.g. Settings.php file where you can have all methods as per your requirement. you can define it with parameter too.
To access any selector and/or method from declared under page dir can be accessible by using the following line.
use Page\Constants as ConstantsPage;
To access any selector from any specific file
FileNamePage::$selectorName;
To access any method, first create the object and then call the method.
E.g.
$settings = new SettingsPage( $I )
$settings->methodName();
To call the method and/pr selector in the same file.
self::selectorName;
self::methodName();
Hope this will be helpful.

How laravel classes are included?

I want to run custom php code in laravel directly without using any routes or http requests..
I hope I can make it clear, I mean, like those online tools that runs php code by writing php code in browser, and then run it, and view result..
I found this handy project (Run-PHP-Code) to run PHP in browser directly, but I can't use models of my laravel project in PHP code..
How can I include laravel 's environment, so that I can for example:
$tag= new Tag;
where Tag is a model in laravel project, that would result into:
Fatal error: Class 'Tag' not found in D:\xampp\htdocs\widgetsRepository\app\controllers\Run-PHP-Code-master\index.php(49) : eval()'d code on line 3
Any idea? this would be very useful!
EDIT
I tried Brian suggestion at his answer, but I got this error now:
Call to a member function connection() on null
at vendor\laravel\framework\src\Illuminate\Database\Eloquent\Model.php
public static function resolveConnection($connection = null)
{
return static::$resolver->connection($connection);
}
so, I think I only need to get database sorted, then I can do experiments easily..
I've never tried to run code from a laravel project directly, I just copy and paste parts of the code into Run PHP Code.
That being said, it should be possible to run the code using the method taken from this StackOverflow question:
The Composer autoload script, to autoload all of your classes:
require __DIR__.'/../bootstrap/autoload.php';
And if you need things from the IoC container, you'll:
$app = require_once __DIR__.'/../bootstrap/start.php';
Then you will be able to do things like:
$post = Post::find(1);

Proceedural Code in Silex or maybe other Microframeworks

I'm taking an application I wrote, a form, and rewriting it in Silex. It was, for various reasons, written like:
page1.php
page1_process.php
page2.php
page2_process.php
page3.php
page3_process.php
Where pageX.php is an HTML form with little PHP code, that passes data to the process script. The process script stores data to a Form object, and serializes the object in the Session.
Currently, I have the pageX.php pages as TWIG template files and they work, but I don't know how to incorporate the logic of the procedural process scripts.
I'm sure I don't copy the actual logic to the controllers.
If I follow your requirements, you just need the same route twice: one for get (displaying the form) and one for post to handle it. In the post controller you just need to include your pageX_process.php and you should be ready to go.
Translated in Silex code it should be something like:
<?php
/**
* if you're using silex-skeleton
* from: https://packagist.org/packages/fabpot/silex-skeleton)
* this file should be src/controllers
*/
// standard setup, like error handling and other route declarations
$app->get('/page1', function() use ($app) {
// you're currently using this (somehow)
$params = []; //set up your template parameters here
return $app['twig']->render('page1.twig', $params);
});
$app->post('/page1_proccess', function() use($app) {
ob_start();
require PATH_TO_LEGACY_FILES_DIR . '/page1_process.php';
return ob_get_clean();
});
From now on, and if you want / find it adequate, you can start to refactor your pageX_process.php pages in a more OOP / Silex way, but you have a starting point with this application architecture.
NOTICE:
you should move your php files away from the web directory (for example legacy/ in the root of your project)
you must point your form handling script (the action parameter) to the new route (you can make it to work using the old route also but requires some little more effort)

Reloading a Class

I have a PHP daemon script running on the command line that can be connected to via telnet etc and be fed commands.
What it does with the command is based on what modules are loaded, which is currently done at the start. (psuedocode below for brevity)
$modules = LoadModules();
StartConnection();
while(true){
ListenForCommands();
}
function LoadModules(){
$modules = Array();
$dir = scandir("modules");
foreach($dir as $folder){
include("modules/".$folder."/".$folder.".php");
$modules[$folder] = new $folder;
}
}
function ListenForCommands(){
if(($command = GetData())!==false){
if(isset($modules[$command])){
$modules[$command]->run();
}
}
}
So, an example module called "bustimes" would be a class called bustimes, living in /modules/bustimes/bustimes.php
This works fine. However, I'd like to make it so modules can be updated on the fly, so as part of ListenForCommands it looks at the filemtime of the module, works out if it's changed, and if so, effectively reloads the class.
This is where the problem comes in, obviously if I include the class file again, it'll error as the class already exists.
All of the ideas I have of how to get around this problem so far are pretty sick and I'd like to avoid doing.
I have a few potential solutions so far, but I'm happy with none of them.
when a module updates, make it in a new namespace and point the reference there
I don't like this option, nor am I sure it can be done (as if I'm right, namespaces have to be defined at the top of the file? That's definitely workaroundable with a file_get_contents(), but I'd prefer to avoid it)
Parsing the PHP file then using runkit-method-redefine to redefine all of the methods.
Anything that involves that kind of parsing is a bad plan.
Instead of including the file, make a copy of the file with everything the same but str_replacing the class name to something with a rand() on the end or similar to make it unique.
Does anyone have any better ideas about how to either a) get around this problem or b) restructure the module system so this problem doesn't occur?
Any advice/ideas/constructive criticism would be extremely welcome!
You should probably load the files on demand in a forked process.
You receive a request
=> fork the main process, include the module and run it.
This will also allow you to run several commands at once, instead of having to wait for each one to run before launching the next.
Fork in php :
http://php.net/manual/en/function.pcntl-fork.php
Tricks with namespaces will fail if module uses external classes (with relative paths in namespace).
Trick with parsing is very dangerous - what if module should keep state? What if not only methods changed, but, for example, name of implemented interface? How it will affect other objects if they have link to instance of reloaded class?
I think #Kethryweryn is something you can try.

parameters & scope in functions

i have a question in PHP related to the parameters of a function and their scope.
I am building an own little template system and currently i keep using:
try {
$ret = include("file.php");
if(!$ret) {
throw new Exception();
}
// Go on here...
}
catch(Exception $e) {
// error handling
}
about 3-4 times in the mainfile index.php. This code first includes the needed file (set by GET parameters in the URL), trys to include it and if it fails it handles all errors. Since this is used 3-4 times in index.php i want to make a function out of it so i can easily call $Template->LoadFile("filename.php"); and this function handles everything for me: Including, Executing the code and error handling.
Not that hard i thought, but when doing so i get a lot of error messages because the variables needed by the included file for its execution are only avaiable in the scope of index.php (where the code was executed before) and not in the scope of the LoadFile() function. What can i do now?
Revert everything back and again use this above code 3-4 times stupidly?
Add all needed variables in LoadFile() as parameters so by using $Template->LoadFile($file,$vars); $vars would be available for use in LoadFile() for the included File? By doing so the given parameters would be huge in some cases. For example if i add an own board, the $vars would contain every board data and thats quite much. Wouldn't that make the template system really slow?
Add the needed variables via parameters as reference? (same as my 2nd suggest, but with less engine slowdown).
use globals? NO!
What options are there else? Thank's a lot :)
You can use option2 but in variety of other ways, have a look at how codeigniter and kohana render their views.
you can do something like
$Template->LoadFile($file, $vars)
where $vars is an array like array('thisIsVariableName' => 'thisIsVariableValue')
or
$Template->file($file)
->vars('thisIsVariableName', thisIsVariableValue)
->multi_var(array('thisIsVariableName2' => 'thisIsVariableValue2'))
->render();
In case of the template size, then you can always split a template into subtemplates.

Categories