I currently have this code in PHP:
public function newFile($folder, $file){
fopen($folder."/".$file, 'w');
}
That I use like this:
newFile('myfolder', 'myfile.txt');
It works fine, but I want to know if it's possible to create a function that I can use like this:
newFile('myfile.txt') inFolder('myfolder');
How can I do this, if it's possible?
I could also use this:
newFile('myfile.txt')->inFolder('myfolder');
I can see that you are trying to achieve a syntax like Objective-C and similar languages, but unfortunately, you can't. Just get used to the PHP syntax.
You could use an array to get named parameters, though:
function newFile($params){
fopen($params['folder']."/".$params['file'], 'w');
}
newFile(array(
'folder' => 'myfolder',
'file' => 'myfile.txt'
));
Alternatively you could use proxies to get to a syntax like: newFile(...)->inFolder(...), but that would definitely be an overkill here.
Here is an example of what you could possibly implement. Such technique is often used, when you need to call a lof of functions of the same object (better readability).
The point is that your functions may return the reference to the same object:
class Creator {
private $file ;
private $folder = "" ;
public function newFile($file){
$this->file = $file ;
return $this ;
}
public function inFolder($folder){
$this->folder = $folder ;
return $this ;
}
public function create(){
return fopen($this->folder."/".$this->file, 'w');
}
}
$creator = new Creator();
$creator
->newFile("test.txt")
->inFolder("test")
->create();
As for the solution of newFile('file')->inFolder('folder') it is possible, but it'd be definite overkill in this situation. Here's an example how to do it, though:
<?php
class File_To_Be_Created {
private $file;
public function __construct($file) {
$this->file = $file;
}
public function inFolder($folder) {
$handle = fopen($folder . '/' . $this->file, 'w');
if ($handle !== false) {
fclose($handle);
}
}
}
function newFile($file) {
return new File_To_Be_Created($file);
}
newFile('myfile.txt')->inFolder('myfolder');
?>
Related
I am trying to load (include file) the GetRiskSummaryCommandHandler.php (GetRiskSummary\CommandHandler) at runtime dynamically, while resolving Route api/risks to HandleCommand (of class CommandHandler) method.
How can I do this? If not can I modify any taken approach including modifying autoloader?
My api class snippet looks like this:
API.php
<?php
abstract class API
{
public function processRequest()
{
$id1 = $this->requestObj->id1;
//$id2 = $this->requestObj->id2;
$endpoint1 = $this->requestObj->endpoint1;
$endpoint2 = $this->requestObj->endpoint2;
$isDestination = in_array($id1, ['first', 'prev', 'next', 'last']);
$numSetEndpoints = (int)isset($endpoint1) + (int)isset($endpoint2);
switch($numSetEndpoints)
{
case 0:
if ($isDestination)
return json_decode($this->_response("No Endpoint: ", $endpoint1));
return json_decode($this->_response("ProjectAIM API"));
case 1:
$className = $endpoint1.'Controller';
break;
case 2:
$className = $endpoint2.'Controller';
break;
}
$class = "GetRiskSummaryCommandHandler";
$method = "HandleCommand";
if (class_exists($class))
{
if (method_exists($class, $method))
{
$response = (new $class($this->requestObj))->{$method}($this->requestObj);
if ($response['Succeeded'] == false)
{
return $response['Result'];
}
else if ($response['Succeeded'] == true)
{
header("Content-Type: application/json");
return $this->_response($response);
}
else if ($response['Result'])
{
header("Content-Type: text/html");
return $this->_response($response);
}
}
}
}
**Command Handler Snippet, uses a Route Attiribute
GetRiskSummaryCommandHandler.php
<?php
namespace GetRiskSummary;
use Infrastructure\CommandHandler;
class GetRiskSummaryCommandHandler extends CommandHandler
{
#[Route("/api/risks", methods: ["GET"])]
public function HandleCommand()
{
$qb = $this->getEntityManager()
->createQueryBuilder();
$qb->select('*')
->from('Risks', 'Risks')
->orderBy('RiskID', 'DESC');
$query = $qb->getQuery();
return $query->getResult();
}
}
Autoloader.php
<?php
namespace Autoloader;
class Autoloader
{
private static function rglob($pattern, $flags = 0) {
$files = glob($pattern, $flags);
foreach (glob(dirname($pattern).'/*', GLOB_ONLYDIR|GLOB_NOSORT) as $dir) {
$files = array_merge($files, self::rglob($dir.'/'.basename($pattern), $flags));
}
return $files;
}
public static function ClassLoader($path)
{
$pathParts = explode("\\", $path);
$path = $pathParts[array_key_last($pathParts)];
$matches = self::rglob("*/$path*");
foreach ($matches as $name)
{
$filePath = realpath($name);
if (file_exists($filePath))
include $filePath;
}
}
}
spl_autoload_register("AutoLoader\AutoLoader::ClassLoader");
I think the biggest missing feature of PHP Attributes would be that as far as I'm aware PHP Attributes are static and aren't evaluated at runtime. They are just glorified comments.
If it was true, we could do some truly amazing things like non-intrusively attaching pre/post-processing functions, just like what you wrote.
They work just like in symfony or doctrine. You can't use variables in them and you must write your own code to search your php class tree for attributes in the code and use php reflection to obtain the information and run the attributes.
To be honest it's pretty disappointing, although maybe it's just the first step that will be fixed in later versions of PHP.
But for now, I think what you're asking for is impossible. Because they are not running dynamically like you appear to be asking.
Is there any way to use a variable of a method, after a recursive call (without sending that as a parameter).
For example:
class Doc {
public function readDoc($file, $recursion = false) {
if ($recursion != false) {
// DO SOMETHING;
}
$filename = $file."Some added text";
$this->readDoc($filename, 1);
}
}
Here, is it possible to use the value of $file sent in the first call (when the readDoc() function is called recursively).
You can create a simple stack with an array, e.g.
class Doc {
private $stack = [];
public function readDoc($file, $recursion=false) {
if($recursion != false)
DO SOMETHING
$this->stack[] = $file;
$filename = $file."Some added text";
$this->readDoc($filename, 1);
}
}
And then get the first index of the array as your $file variable.
you could also use an anonymous function to work in a different scope something like this:
public function test($file, $recursion = false)
{
$rec = function($r) use ($file, &$rec)
{
if($r !== false) {
}
$filename = $file.'test';
return $rec($r);
};
return $rec($recursion);
}
in this case the $file variable always stays the same
(be aware that the above example creates an infinite-loop)
I'm trying to edit a template system so where I can use params such as [title] and it'll show my title in the included page. But I also want to be able to use php code inside of it and be able to execute that code. But I am having difficult getting them both to work at the same time.
I have tried to use include instead of file_get_Contents but when I use include, the params no longer work. However when I use file_get_contents the php doesnt work, and doesnt show.
My code:
class Template {
public function __construct($directory){
$this->dir = $directory;
}
public function setPage($pageName){
$this->directory = 'lib/' . $this->dir . '/' . $pageName . '.php';
if(file_exists($this->directory)) {
$Content = file_get_contents($this->directory);
}
}
public function newParam($trans, $val){
$this->param['[*' . $trans . '*]'] = $val;
}
public function setParams($element){
$element = str_replace(array_keys($this->param), array_values($this->param), $element);
return $element;
}
public function Create(){
die($this->setParams($Content));
}
}
Hope someone can help. Thanks
I have the following situation.
I have a class with a lot of functions. Each function starts with executing the same method. Is there a way that I can like implement this method into the function so that it is executed automatically?
Here is an example:
class test
{
static function_1($param) {some_method($param); other stuff....}
static function_2($param) {some_method($param); other stuff then function 1....}
static function_3($param) {some_method($param); other stuff then function 1 and function 2....}
}
So is there a way to execute some_method(); automaticly without declaring it in each function?
Thanks in advance!
Whole code:
<?php if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/*
* The Assets Library
*
* This class let's you add assets (javascripts, stylesheets and images) way easier..
*/
class Assets {
private $css_url;
private $js_url;
private $img_url;
public function __construct()
{
$CI =& get_instance();
$CI->config->load('assets');
$asset_url = base_url() . $CI->config->item('assets_dir');
$this->css_url = $asset_url . $CI->config->item('css_dir_name');
$this->js_url = $asset_url . $CI->config->item('js_dir_name');
$this->img_url = $asset_url . $CI->config->item('img_dir_name');
}
// Returns the css html link
public function css_html_link($filename)
{
// Check whether or not a filetype was given
$filename = $this->_add_filetype($filename, 'css');
$link = '<link type="text/css" rel="stylesheet" href="' . $this->css_url . $filename . '" />';
return $link;
}
// Returns the css link
public function css_link($filename)
{
$filename = $this->_add_filetype($filename, 'css');
return $this->css_url . $filename;
}
// Returns the js html link
public function js_html_link($filename)
{
$filename = $this->_add_filetype($filename, 'js');
$script = '<script type="text/javascript" src="' . $this->js_url . $filename . '"></script>';
return $script;
}
// Return the js link
public function js_link($filename)
{
$filename = $this->_add_filetype($filename, 'js');
return $this->js_url . $filename;
}
// Returns the image html tag
public function img_html_link($filename, $rel = NULL)
{
// Get the filename without the filetype
$alt_text = substr($filename, 0, strpos($filename, '.')+1);
$alt_text = 'alt="'.$alt_text.'"';
// If relation is giving, use it
$img_rel = ($rel !== FALSE) ? 'rel="' . $rel . '"' : '';
$image = '<img src="' . $this->img_url . $filename . '" '.$rel.' ' . $alt_text . '/>';
return $image;
}
// Return the image link
public function img_link($filename)
{
return $this->img_url . $filename;
}
// Check whether or not a filetype was specified in $file, if not, it will be added
private function _add_filetype($file, $type)
{
if(strpos($file, '.' . $type) === FALSE)
{
$file = $file . '.' . $type;
}
return $file;
}
}
/* End of file assets.php */
/* Location: ./application/libraries/assets.php */
every time you initiate the class, it calls the __construct() function, or in PHP 4 (I hope you are not using php 4) it uses the function with the same name as the class
If you do this, it should work for every initiate of the class:
function __construct($param){
some_method($param);
}
if you call multiple functions in the same initiation of the class, you could do this:
var $param;
function __construct($param){
$this->param = $param;
}
function doMethod(){
some_method($this->param);
}
function function_1()
{
$this->doMethod();
}
Calling the class multiple times, with different params. Perhaps try this approach:
function __call($function, $param){
some_method($param);
switch ($function){
case 'function1':
$this->function1($param);
break;
/// etc..
}
}
I'm afraid that in this case the answer is 'no'.
You're not 'declaring' some_method() each time, you are calling it. If you don't call it, it can't run, so you have to call it each time.
Cut & paste.....
Why not paste your actual code here, some refactoring may help.
Edit after seeing actual code
I can't see the problem with your existing code. It is clear and you will know what it does in a year's time. I would keep it as it is. The answer you accepted will work, but it is obfuscating your code. You will have problems working out what you did and why you did it in when you come back to maintain your code in the future.
You could create a class containing an instance of the class test (composition) and implement its __call magic method. Something akin to:
class testWrapper
{
private $test;
function __construct()
{
$this->test = new Test();
}
function __call($name, $args)
{
call_user_func_array(array($this->test, 'some_method'), $args);
call_user_func_array(array($this->test, $name), $args);
}
}
You then call methods from the test class on the instance object of testWrapper.
You can further refine the logic in the __call method to only call some_method() based on the passed-in method name, etc.
I'm building a little MVC system (learning) and I have some problems with showing variables in my view files.
This is from my View class:
private $vars = array();
public function __set($key, $value)
{
$this->vars[$key] = $value;
}
public function __get($key)
{
return $this->vars[$key];
}
public function __toString()
{
return $this->vars[$key];
}
public function show($file)
{
global $router;
$folder = strtolower($router->current_controller);
$path = VIEWPATH.$folder.'/'.$file.'.phtml';
if ( ! file_exists($path))
{
die("Template: $file, not found");
}
include ($path);
}
And here is from my controller:
$test = new View();
$test->name = 'karl';
$test->show('name_view');
And the view file (name_view)
echo $name // doesn't work
echo $this->name // Works
What am I doing wrong? Perhaps I haft to make something global?
THX / Tobias
EDIT: I just extracted the vars array in the view class right before I include the view file and then it worked.. Thank you for all help.
There is no $key in __toString()!
Also __toString() doesn't accept any parameters!
Test it with this:
public function __toString()
{
return json_encode($this->vars);
}
After your edit I realized that your problem is not on the __toString() method (you can just delete it since you're not using it). Doing echo $this->name is the correct way to show variables from inside your view in your case, however if you want to just do echo $name may I suggest a different approach?
function View($view)
{
if (is_file($view) === true)
{
$arguments = array_slice(func_get_args(), 1);
foreach ($arguments as $argument)
{
if (is_array($argument) === true)
{
extract($argument, EXTR_OVERWRITE);
}
}
require($view);
}
}
Use the View function like this:
$data = array
(
'name' => 'karl',
);
View('/path/to/your/name_view.phtml', $data);
Now it should work just by doing echo $name;, you can adapt it to your View class if you want to. If that doesn't work, try changing the name_view view extension to .php.