Created
August 14, 2021 16:47
-
-
Save mattkenefick/e4e151e027f6c77202e4c112514cdb81 to your computer and use it in GitHub Desktop.
Magic safety in PHP
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
namespace App\Console\Commands; | |
use Illuminate\Console\Command; | |
use Illuminate\Support\Facades\Log; | |
use Illuminate\Support\Facades\Storage; | |
abstract class BaseCommand extends Command | |
{ | |
/** | |
* If we are expecting a dry run here | |
* | |
* For destructive calls, use --dryrun=false | |
* | |
* We are intentionally using "false" explicitly because | |
* we don't want accidental values like "0" causing | |
* damaging effects. | |
* | |
* @var boolean | |
*/ | |
protected bool $dryrun = true; | |
/** | |
* Execute the console command. | |
* | |
* @return int | |
*/ | |
public function handle() | |
{ | |
$dryrun = $this->option('dryrun') === 'false'; | |
// Set options | |
$this->dryrun = $dryrun ? !$dryrun : $this->dryrun; | |
} | |
/** | |
* Magical CALL method that checks for dynamic method | |
* names. Allows us to write "safelyMyFunction" but | |
* reference "myFunction" | |
* | |
* @param string $method | |
* @param mixed $arguments | |
* @return void | |
*/ | |
public function __call($method, $arguments) | |
{ | |
preg_match('/(safely|test)(.*)/', $method, $matches); | |
// Check if we have any matches | |
if (isset($matches)) { | |
$protectedMethod = $matches[1] . 'Call'; | |
$classMethod = lcfirst($matches[2]); | |
// Check if modified method exists on this class | |
// e.g. "safelyCall(...)" or "testCall(...)" | |
if (method_exists($this, $protectedMethod) && method_exists($this, $classMethod)) { | |
return $this->$protectedMethod($classMethod, $arguments); | |
} | |
} | |
} | |
/** | |
* Special call using prefix "safely" | |
* | |
* @return void | |
*/ | |
protected function safelyCall(string $classMethod, $arguments) | |
{ | |
// Check if it's a dry run | |
if ($this->dryrun) { | |
$this->log("🟡 Not executing `$classMethod` on a dry-run.\n"); | |
return false; | |
} | |
return call_user_func_array(array($this, $classMethod), $arguments); | |
} | |
// ... | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// Rest of class... | |
/** | |
* Special call using prefix "safely" | |
* | |
* @param string $classMethod | |
* @param mixed $arguments | |
* @return void | |
*/ | |
protected function safelyCall(string $classMethod, $arguments) | |
{ | |
// Check if it's a dry run | |
if ($this->dryrun) { | |
$this->log("🟡 Not executing `$classMethod` on a dry-run.\n"); | |
return false; | |
} | |
return call_user_func_array(array($this, $classMethod), $arguments); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// Rest of class... | |
/** | |
* Search and destroy unused content | |
* | |
* @return void | |
*/ | |
protected function cleanContentTable() | |
{ | |
$sql = " | |
SELECT `content`.* | |
FROM `content` | |
LEFT JOIN `user` ON `user`.`content_id` = `content`.`id` | |
WHERE (`user`.`id` IS NULL AND `content`.`type` = 1234) | |
"; | |
// Determine rows found | |
$ids = array_column(DB::select($sql), 'id'); | |
// Checks to see if it's a dry run or not first | |
$this->safelyRemoveContentByIds($ids); | |
// Does NOT test for dry run, just removes content | |
// $this->removeContentByIds($ids); | |
} | |
/** | |
* Remove content | |
* | |
* @param array $ids | |
* @return void | |
*/ | |
protected function removeContentByIds(array $ids = []) | |
{ | |
// Delete content... | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
// Rest of class... | |
/** | |
* Magical CALL method that checks for dynamic method | |
* names. Allows us to write "safelyMyFunction" but | |
* reference "myFunction" | |
* | |
* @param string $method | |
* @param mixed $arguments | |
* @return void | |
*/ | |
public function __call($method, $arguments) | |
{ | |
preg_match('/(safely|test)(.*)/', $method, $matches); | |
// Check if we have any matches | |
if (isset($matches)) { | |
$protectedMethod = $matches[1] . 'Call'; | |
$classMethod = lcfirst($matches[2]); | |
// Check if modified method exists on this class | |
// e.g. "safelyCall(...)" or "testCall(...)" | |
if (method_exists($this, $protectedMethod) && method_exists($this, $classMethod)) { | |
return $this->$protectedMethod($classMethod, $arguments); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment