Is there a way to implement method pointers in PHP?
I keep getting the following error:
Fatal error: Call to undefined function create_jpeg() in /Users/sky/Documents/images.php on line 175
This is line 175:
if ($this->ImageType_f[$pImageType]($pPath) != 0)
class CImage extends CImageProperties
{
private $Image;
private $ImagePath;
private $ImageType;
private function create_jpeg($pFilename)
{
if (($this->Image = imagecreatefromjepeg($pFilename)) == false)
{
echo "TEST CREATION JPEG\n";
echo "Error: ".$pFilename.". Creation from (JPEG) failed\n";
return (-1);
}
return (0);
}
private function create_gif($pFilename)
{
if (($this->Image = imagecreatefromgif($pFilename)) == false)
{
echo "Error: ".$pFilename.". Creation from (GIF) failed\n";
return (-1);
}
return (0);
}
private function create_png($pFilename)
{
if (($this->Image = imagecreatefrompng($pFilename)) == false)
{
echo "Error: ".$pFilename.". Creation from (PNG) failed\n";
return (-1);
}
return (0);
}
function __construct($pPath = NULL)
{
echo "Went through here\n";
$this->Image = NULL;
$this->ImagePath = $pPath;
$this->ImageType_f['JPEG'] = 'create_jpeg';
$this->ImageType_f['GIF'] = 'create_gif';
$this->ImageType_f['PNG'] = 'create_png';
}
function __destruct()
{
if ($this->Image != NULL)
{
if (imagedestroy($this->Image) != true)
echo "Failed to destroy image...";
}
}
public function InitImage($pPath = NULL, $pImageType = NULL)
{
echo "pPath: ".$pPath."\n";
echo "pImgType: ".$pImageType."\n";
if (isset($pImageType) != false)
{
if ($this->ImageType_f[$pImageType]($pPath) != 0)
return (-1);
return (0);
}
echo "Could not create image\n";
return (0);
}
}
Just call the method you need with $this->$method_name() where $method_name is a variable containing the method you need.
Also it is possible using call_user_func or call_user_func_array
What is callable is described here: http://php.net/manual/ru/language.types.callable.php
So assuming $this->ImageType_f['jpeg']' must be callable: array($this, 'create_jpeg').
Alltogether: call_user_func($this->ImageType_f[$pImageType], $pPath) is the way to do it.
Or if $this->ImageType_f['jpeg'] = 'create_jpeg':
$this->{$this->ImageType_f['jpeg']]($pPath);
Some documentation on functions I mentioned here:
http://us2.php.net/call_user_func
http://us2.php.net/call_user_func_array
Your problem is is line:
if ($this->ImageType_f[$pImageType]($pPath) != 0)
-since $this->ImageType_f[$pImageType] will result in some string value, your call will be equal to call of global function, which does not exists. You should do:
if ($this->{$this->ImageType_f[$pImageType]}($pPath) != 0)
-but that looks tricky, so may be another good idea is to use call_user_func_array():
if (call_user_func_array([$this, $this->ImageType_f[$pImageType]], [$pPath]) != 0)
I think you need to use this function call_user_func
In your case call will looks like
call_user_func(array((get_class($this), ImageType_f[$pImageType]), array($pPath));
Related
I can't get PHPUnit's Code Coverage tool to mark this else statement as covered even though it must be or the following line could not be covered. Elsewhere in the same class another line that contains only } else { is correctly marked as covered.
if (is_string($externalId) && $externalId != '') {
$sitesIds[] = $externalId;
} else if ($regionName != null && $regionName != '') {
$sitesIds = $this->sitesService->getSites($regionName);
if (!is_array($sitesIds) || count($sitesIds) == 0) {
throw new \Exception(self::NO_MATCHING_REGION, '404');
}
} else {
throw new \Exception(self::BAD_REQUEST.'. Should specify station or region', '400');
}
Since else doesn't actually do anything (it can be considered just a label) it won't get covered.
Your problem is that you don't have a test where (is_string($externalId) && $externalId != '') is false, ($regionName != null && $regionName != '') is true and (!is_array($sitesIds) || count($sitesIds) == 0) is false. (You might want to be more specific by using not exactly equal to !== instead of not equal to !=: ($externalId !== '') & ($regionName !== null && $regionName !== ''))
If you can get $sitesIds = $this->sitesService->getSites($regionName); to return an array with at least one element, your red line will be covered and turn green.
The red line is telling you that the closing brace } before the else is technically reachable, but you have no tests that cover it.
With slightly modified source:
class A
{
const NO_MATCHING_REGION = 1;
const BAD_REQUEST = 2;
private $sitesService = ['a' => ['AA'], 'b'=>12];
public function a($externalId, $regionName)
{
$sitesIds = [];
if (is_string($externalId) && $externalId != '') {
$sitesIds[] = $externalId;
} else {
if ($regionName != null && $regionName != '') {
$sitesIds = $this->sitesService[$regionName];
if (!is_array($sitesIds) || count($sitesIds) == 0) {
throw new \Exception(self::NO_MATCHING_REGION, '404');
}
} else {
throw new \Exception(self::BAD_REQUEST.'. Should specify station or region', '400');
}
}
return $sitesIds;
}
}
The test
class ATest extends \PHPUnit_Framework_TestCase
{
/**
* #dataProvider data
*/
public function testOk($id, $reg, $res)
{
$a = new A;
$r = $a->a($id, $reg);
$this->assertEquals($res, $r);
}
public function data()
{
return [
['a', 1, ['a']],
[1,'a', ['AA']]
];
}
/**
* #dataProvider error
* #expectedException \Exception
*/
public function testNotOK($id, $reg)
{
$a = new A;
$a->a($id, $reg);
}
public function error()
{
return [
[1,'b'],
[1,null]
];
}
}
Covers the else line:
PHP 5.6.15-1+deb.sury.org~trusty+1
PHPUnit 4.8.21
So I am getting the following error.
Fatal error: Call to undefined method CI_Form_validation::error_array() in /home/kmgpdev/public_html/projects/lm/application/controllers/api.php on line 64
Line 63 through 66 reads
if($this->form_validation->run() == false) {
$this->output->set_output(json_encode(['result' => 0, 'error' => $this->form_validation->error_array()]));
return false;
}
If I remove the 64th line it works fine, just no errors are produced.
Also here is my MY_Form_validation.php file I created as a custom library.
class MY_Form_validation extends CI_Form_validation
{
public function __construct($config = array())
{
parent::__construct($config);
}
public function error_array()
{
if(count($this->_error_array > 0)) {
return $this->_error_array;
}
}
}
So it running well in localhost, xampp and when I upload to my ubuntu server then it happend this error, I cannot figure out why this error is coming up. I'm using php 5.5, Any suggestions?
Thanks in advance.
To get the first error message, I have put a utility function like this directly under //system/libraries/Form_validation.php. Otherwise you can use $this->form_validation->error_string() instead of directly picking error array. In most cases, you would want your user to see the error as a string :
function first_error_string($prefix = '', $suffix = '')
{
// No errrors, validation passes!
if (count($this->_error_array) === 0)
{
return '';
}
if ($prefix == '')
{
$prefix = $this->_error_prefix;
}
if ($suffix == '')
{
$suffix = $this->_error_suffix;
}
// Generate the error string
$str = '';
foreach ($this->_error_array as $val)
{
if ($val != '')
{
$str .= $prefix.$val.$suffix;
break;
}
}
return $str;
}
I Use a json onclick script for triggering a php function.
I call the php function with:
$('#dtable').on('click', '[name=option3]', function () {
var select = $(this);
var id = select.attr('id');
$.post('index.php/stop/'+id+'', function(json) {
if (json && json.status) {
$("#failure").show().delay(2500).fadeOut(1500);
} else {
$("#success").show().delay(2500).fadeOut(1500);
}
}
);
} );
If the item is trigger he calls a slim property in my index.php
$admin->slim->post('/stop/:action', function($action) use ($admin) {
$admin->slim->contentType('application/json');
echo json_encode($admin->cont->Stop($action));
After this he triggert the function
function Stop($action) {
$port = $action;
$connection = #fsockopen($this->cfg->base_host, $port, $errno, $errstr, 1);
if (!$connection) {
return false;
} else {
$pid = $this->db->query("SELECT pid FROM testdb WHERE port='" . $port . "'", SQL_ALL, SQL_ASSOC);
if ($pid == "") {
return false;
} else {
......
}
}
}
}
}
the only thing is that the answer from json is always success
but there is no return from true or false from the function
Does someone knows what i doing wrong or can someone give me some advice.
Added more information about the function
Use alert(json); before if (json && json.status) to see what you get. I'm sure json is not what you expect. It seems json == false (because function Stop() return false) and there is no json.status - or maybe rest of your Stop function return something more.
Take the following function for example:
private function connect($method, $target = $this->_config->db()) {
try {
if (!($this->_pointer = #fopen($target, $method)))
throw new Exception("Unable to connect to database");
} catch (Exception $e) {
echo $e->getMessage();
}
}
As you can see I inserted the function $this->_config->db() into the parameter $target as it's default value. I understand this is not the correct syntax and am just trying to explain my aim.
$this->_config->db() is a getter function.
Now I know I can use an anonymous function and call it via $target later, but I want $target to also accept direct string values.
How could I give it a default value of the whatever is returned by $this->_config->db() and still be able to overwrite it with a string value?
Why not accept NULL values by default (test with is_null()) and if so call your default function?
You can use is_callable() and is_string().
private function connect($method, $target = NULL) {
if (is_callable($target)) {
// We were passed a function
$stringToUse = $target();
} else if (is_string($target)) {
// We were passed a string
$stringToUse = $target;
} else if ($target === NULL) {
// We were passed nothing
$stringToUse = $this->_config->db();
} else {
// We were passed something that cannot be used
echo "Invalid database target argument";
return;
}
try {
if (!($this->_pointer = #fopen($stringToUse, $method)))
throw new Exception("Unable to connect to database");
} catch (Exception $e) {
echo $e->getMessage();
}
}
I would perform a check to see if a value was passed and call my function in a simple check inside the method:
private function connect($method, $target = '') {
try {
if ($target === '') {
$target = $this->_config->db()
}
if (!($this->_pointer = #fopen($target, $method))) {
throw new Exception("Unable to connect to database");
}
} catch (Exception $e) {
echo $e->getMessage();
}
}
I have a class with a couple of methods
deleteUploadedFile() and currentUploadedFiles().
currentUploadedFiles(), basically loops over a session array and displays it on screen, simple as. Code sample:
function currentUploadedFiles()
{
if(isset($_SESSION['fileArray']) && $this->count > 0)
{
echo '<p style="clear:both">Current files uploaded list:</p>';
echo '<ol>';
foreach($_SESSION['fileListing'] as $key => $value )
{
echo '<li>'. $value .' [Remove File]</li>';
}
echo "</ol>\n\r";
echo "<p> Current file size allowance: ". $this->_returnRemainingSessionFileSize() ." of 8 MB";
} else {
echo '<p style="clear:both">No files have been uploaded yet</p>';
}
if($this->deleteUploadedFile() === true)
{
echo '<p>File has now been deleted from our records.</p>';
}
}
the deleteUploadedFile() method, basically when form is submitted it deletes file from the server and removes the entry from the session array. Sample code:
function deleteUploadedFile()
{
(int) $id = $_GET['id'];
(bool) $deleted = false;
if (file_exists($this->target_path.'/'.$_SESSION['fileArray'][$id]))
{
$_SESSION['fileSize'] -= $this->_checkSessionFileSize($id);
if (unlink($this->target_path.'/'.$_SESSION['fileArray'][$id]))
{
$deleted = true; //'<p>File has now been deleted from our records.</p>';
unset($_SESSION['fileArray'][$id]);
unset($_SESSION['fileListing'][$id]);
}
}
return $deleted;
}
my controller, basically checks if file id# isset, then checks if the array id# isset, then calls the deleteUploadedFile() method and then calls the currentUploadedFiles() method.
Question is, why when I var_dump $deleted var in deleteUploadedFile() I get bool(true) but inside the currentUploadedFiles() method I get bool(false). Sounds like I'm messing up the scope somehow?
Looks like $deleted is in the local scope of the delete function.
Something like the following should work.
class theClass
{
function __construct()
{
$this->deleted = false
}
function delete()
{
$this->deleted = true;
}
function upload()
{
var_dump($this->deleted);
}
}