在Laravel 5上定制帮助程序的最佳实践

我想创build一些帮助器(函数),以避免在L5风格的一些视图之间重复代码:

view.blade.php

<p>Foo Formated text: {{ fooFormatText($text) }}</p> 

他们基本上是文本格式function。 在哪里以及如何将这些function放在一个文件?

在app文件夹中创build一个helpers.php文件,并使用composer加载它:

 "autoload": { "classmap": [ ... ], "psr-4": { "App\\": "app/" }, "files": [ "app/helpers.php" // <---- ADD THIS ] }, 

将其添加到composer.json文件后,运行以下命令:

 composer dump-autoload 

我最初的想法也是composer php自动加载,但对我来说,并不觉得Laravel对我很好。 L5大量使用服务提供商,它们是引导您的应用程序的原因。

首先,我在我的app目录中创build了一个名为Helpers的文件夹。 然后,在Helpers文件夹中,我添加了我想要添加的函数的文件。 拥有一个包含多个文件的文件夹可以避免一个大文件变得太长而难以pipe理。

接下来我通过运行artisan命令创build了一个HelperServiceProvider.php

 artisan make:provider HelperServiceProvider 

register方法中,我添加了这个片段

 public function register() { foreach (glob(app_path().'/Helpers/*.php') as $filename){ require_once($filename); } } 

最后在provider数组中的config/app.php中注册服务提供者

 'providers' => [ 'App\Providers\HelperServiceProvider', ] 

现在你的Helpers目录中的任何文件都被加载,并可以使用。

更新2016-02-22

在这里有很多很好的select,但是如果我的答案适合你,我会继续做这样一个包装助手。 您既可以使用该软件包获取灵感,也可以随时使用Composer下载。 它有一些内置的帮助器,我经常使用(但默认情况下都是非活动的),并允许您使用简单的Artisan生成器来创build自己的定制帮助器。 它还解决了一个响应者使用映射器的build议,并允许您明确定义要加载的自定义助手,或者默认情况下会自动将所有PHP文件加载到助手目录中。 反馈和PR非常感谢!

 composer require browner12/helpers 

Github: browner12 / helpers

Laravel 5中的自定义类,简单的方法

这个答案适用于Laravel内的一般自定义类。 有关更多刀片特定的答案,请参阅Laravel 5中的自定义刀片指令

第1步:创build您的助手(或其他自定义类)文件,并给它一个匹配的命名空间。 写下你的课程和方法:

 <?php // Code within app\Helpers\Helper.php namespace App\Helpers; class Helper { public static function shout(string $string) { return strtoupper($string); } } 

第2步:创build一个别名:

 <?php // Code within config/app.php 'aliases' => [ ... 'Helper' => App\Helpers\Helper::class, ... 

第3步:在刀片模板中使用它:

 <!-- Code within resources/views/template.blade.php --> {!! Helper::shout('this is how to use autoloading correctly!!') !!} 

额外学分:在您的Laravel应用程序的任何地方使用此课程:

 <?php // Code within app/Http/Controllers/SomeController.php namespace App\Http\Controllers; use Helper; class SomeController extends Controller { public function __construct() { Helper::shout('now i\'m using my helper class in a controller!!'); } ... 

资料来源: http : //www.php-fig.org/psr/psr-4/

为什么它的作品: https : //github.com/laravel/framework/blob/master/src/Illuminate/Support/ClassLoader.php

自动加载源自: http : //php.net/manual/en/language.oop5.autoload.php

JeffreyWay在这个Laracasts Discussion中提出了这个build议。

  1. 在你的app/Http目录中,创build一个helpers.php文件并添加你的函数。
  2. composer.json ,在autoload块中,添加"files": ["app/Http/helpers.php"]
  3. 运行composer dump-autoload

通过筛选SO和Google的各种答案,我仍然找不到一个最佳方法。 大多数的答案build议我们离开应用程序,并依靠第三方工具composer php来完成这项工作,但我不相信联接到一个工具只是包含一个文件是明智的。

安德鲁·布朗的答案与我认为应该接近的答案最接近,但是(至less在5.1),服务提供者的步骤是不必要的。 Heisian的回答强调了PSR-4的使用,这使我们更接近了一步。 这是我在视图中的助手的最终实现:

首先,在你的apps目录的任意位置创build一个帮助文件,命名空间为:

 namespace App\Helpers; class BobFinder { static function bob() { return '<strong>Bob?! Is that you?!</strong>'; } } 

接下来,在aliases数组config\app.php ,将您的类别别名为config\app.php

 'aliases' => [ // Other aliases 'BobFinder' => App\Helpers\BobFinder::class ] 

而这应该是你需要做的一切。 PSR-4和别名应该帮助你的观点,所以在你看来,如果你input:

 {!! BobFinder::bob() !!} 

它应该输出:

 <strong>Bob?! Is that you?!</strong> 

自定义刀片指令在Laravel 5

是的,还有另一种方法可以做到这一点!

步骤1:注册一个自定义的Blade指令:

 <?php // code in app/Providers/AppServiceProvider.php namespace App\Providers; use Illuminate\Support\ServiceProvider; use Blade; // <-- This is important! Without it you'll get an exception. class AppServiceProvider extends ServiceProvider { /** * Bootstrap any application services. * * @return void */ public function boot() { // Make a custom blade directive: Blade::directive('shout', function ($string) { return trim(strtoupper($string), '(\'\')'); }); // And another one for good measure: Blade::directive('customLink', function () { return '<a href="#">Custom Link</a>'; }); } ... 

第2步:使用您自定义的Blade指令:

 <!-- // code in resources/views/view.blade.php --> @shout('this is my custom blade directive!!') <br /> @customLink 

输出:

这是我的定制刀片指令!
自定义链接


来源: https : //laravel.com/docs/5.1/blade#extending-blade

附加阅读: https : //mattstauffer.co/blog/custom-conditionals-with-laravels-blade-directives


如果您想了解如何最好地制作可在任何地方使用的自定义类 ,请参阅Laravel 5中的自定义类,简单方法

这是我的HelpersProvider.php文件:

 <?php namespace App\Providers; use Illuminate\Support\ServiceProvider; class HelperServiceProvider extends ServiceProvider { protected $helpers = [ // Add your helpers in here ]; /** * Bootstrap the application services. */ public function boot() { // } /** * Register the application services. */ public function register() { foreach ($this->helpers as $helper) { $helper_path = app_path().'/Helpers/'.$helper.'.php'; if (\File::isFile($helper_path)) { require_once $helper_path; } } } } 

你应该在app文件夹下创build一个名为Helpers的文件夹,然后在里面创build名为whatever.php文件,并在$ helpers数组内添加string。

完成!

编辑

我不再使用这个选项,我目前正在使用composer php加载静态文件,如帮手。

您可以直接在以下位置添加助手:

 ... "autoload": { "files": [ "app/helpers/my_helper.php", ... ] }, ... 

对于我的Laravel项目中的自定义帮助程序库,我在Laravel/App目录和Libraries目录中创build了一个名为Libraries的文件夹,我为不同的帮助程序库创build了各种文件。

创build我的帮助文件后,我只需将这些文件包含在我的composer.json文件中

 ... "autoload": { "classmap": [ "database" ], "files": [ "app/Libraries/commonFunctions.php" ], "psr-4": { "App\\": "app/" } }, ... 

并执行

 composer dumpautoload 

由于OP要求最佳实践 ,我认为我们在这里仍然缺less一些好的build议。

一个helpers.php文件远不是一个好的做法。 首先,因为你混合了许多不同types的函数,所以你违背了良好的编码原则。 此外,这不仅损害代码文档,还会影响像Cyclomatic ComplexityMaintainability IndexHalstead Volume这样的代码度量。 你有越多的function越糟糕。

代码文档可以使用像phpDocumentor这样的工具,但使用Sami它不会呈现程序文件 。 Laravel API文档就是这种情况 – 没有帮助函数文档: https ://laravel.com/api/5.4

代码度量可以使用PhpMetrics等工具进行分析。 使用PhpMetrics版本1.x来分析Laravel 5.4框架代码会给你src / Illuminate / Foundation / helpers.phpsrc / Illuminate / Support / helpers.php文件的CC / MI / HV指标非常糟糕。

多个上下文帮助文件(例如, string_helpers.phparray_helpers.php等)肯定会改善那些不好的度量,从而导致更容易的代码维护。 根据所使用的代码文档生成器,这将是足够好的。

可以通过使用具有静态方法的助手类来进一步改进,以便可以使用命名空间对其进行上下文化。 就像Laravel已经Illuminate\Support\StrIlluminate\Support\Arr类一样。 这改进了代码度量/组织和文档。 类别别名可以用来使它们更易于使用。

通过类的构造使得代码组织和文档更好,但是另一方面,我们最终放弃了那些简短易记的全局函数。 我们可以通过为这些静态类方法创build函数别名来进一步改进这种方法。 这可以手动或dynamic完成。

Laravel在内部使用第一种方法,通过在映射到静态类方法的过程助手文件中声明函数。 这可能不是理想的事情,因为你需要重新声明所有的东西(docblocks /参数)。
我个人使用一个HelperServiceProvider类的dynamic方法,在执行时创build这些函数:

 <?php namespace App\Providers; use Illuminate\Support\ServiceProvider; class HelperServiceProvider extends ServiceProvider { /** * The helper mappings for the application. * * @var array */ protected $helpers = [ 'uppercase' => 'App\Support\Helpers\StringHelper::uppercase', 'lowercase' => 'App\Support\Helpers\StringHelper::lowercase', ]; /** * Bootstrap the application helpers. * * @return void */ public function boot() { foreach ($this->helpers as $alias => $method) { if (!function_exists($alias)) { eval("function {$alias}(...\$args) { return {$method}(...\$args); }"); } } } /** * Register the service provider. * * @return void */ public function register() { // } } 

有人可以说这是结束工程,但我不这么认为。 它工作得很好,与预期相反,至less在使用PHP 7.x时不会花费相关的执行时间。

这里是我为创buildLaravel 5外墙而创build的一个bash shell脚本。

在你的Laravel 5安装目录下运行。

像这样调用它:

 make_facade.sh -f <facade_name> -n '<namespace_prefix>' 

例:

 make_facade.sh -f helper -n 'App\MyApp' 

如果您运行该示例,它将在'your_laravel_installation_dir / app / MyApp'下创build目录FacadesProviders

它会创build以下3个文件,并将其输出到屏幕上:

 ./app/MyApp/Facades/Helper.php ./app/MyApp/Facades/HelperFacade.php ./app/MyApp/Providers/HelperServiceProvider.php 

完成后,将显示类似于以下内容的消息:

 =========================== Finished =========================== Add these lines to config/app.php: ---------------------------------- Providers: App\MyApp\Providers\HelperServiceProvider, Alias: 'Helper' => 'App\MyApp\Facades\HelperFacade', 

所以更新'config / app.php'中的Providers和Alias列表

运行composer -o dumpautoload

“./app/MyApp/Facades/Helper.php”原本是这样的:

 <?php namespace App\MyApp\Facades; class Helper { // } 

现在只需在“./app/MyApp/Facades/Helper.php”中添加你的方法。

这是什么“./app/MyApp/Facades/Helper.php”看起来像我添加了一个帮手function。

 <?php namespace App\MyApp\Facades; use Request; class Helper { public function isActive($pattern = null, $include_class = false) { return ((Request::is($pattern)) ? (($include_class) ? 'class="active"' : 'active' ) : ''); } } This is how it would be called: =============================== {!! Helper::isActive('help', true) !!} 

这个函数需要一个模式,可以接受一个可选的第二个布尔参数。

如果当前的URL匹配传递给它的模式,那么它将输出'active'(或者如果你在函数调用中添加'true'作为第二个参数,那么'class ='active'')。

我用它来突出显示活动的菜单。

以下是我的脚本的源代码。 我希望你觉得它有用,请让我知道如果你有任何问题。

 #!/bin/bash display_syntax(){ echo "" echo " The Syntax is like this:" echo " ========================" echo " "$(basename $0)" -f <facade_name> -n '<namespace_prefix>'" echo "" echo " Example:" echo " ========" echo " "$(basename $0) -f test -n "'App\MyAppDirectory'" echo "" } if [ $# -ne 4 ] then echo "" display_syntax exit else # Use > 0 to consume one or more arguments per pass in the loop (eg # some arguments don't have a corresponding value to go with it such # as in the --default example). while [[ $# > 0 ]] do key="$1" case $key in -n|--namespace_prefix) namespace_prefix_in="$2" echo "" shift # past argument ;; -f|--facade) facade_name_in="$2" shift # past argument ;; *) # unknown option ;; esac shift # past argument or value done fi echo Facade Name = ${facade_name_in} echo Namespace Prefix = $(echo ${namespace_prefix_in} | sed -e 's#\\#\\\\#') echo "" } function display_start_banner(){ echo '**********************************************************' echo '* STARTING LARAVEL MAKE FACADE SCRIPT' echo '**********************************************************' } # Init the Vars that I can in the beginning function init_and_export_vars(){ echo echo "INIT and EXPORT VARS" echo "====================" # Substitution Tokens: # # Tokens: # {namespace_prefix} # {namespace_prefix_lowerfirstchar} # {facade_name_upcase} # {facade_name_lowercase} # namespace_prefix=$(echo ${namespace_prefix_in} | sed -e 's#\\#\\\\#') namespace_prefix_lowerfirstchar=$(echo ${namespace_prefix_in} | sed -e 's#\\#/#g' -e 's/^\(.\)/\l\1/g') facade_name_upcase=$(echo ${facade_name_in} | sed -e 's/\b\(.\)/\u\1/') facade_name_lowercase=$(echo ${facade_name_in} | awk '{print tolower($0)}') # Filename: {facade_name_upcase}.php - SOURCE TEMPLATE source_template='<?php namespace {namespace_prefix}\Facades; class {facade_name_upcase} { // } ' # Filename: {facade_name_upcase}ServiceProvider.php - SERVICE PROVIDER TEMPLATE serviceProvider_template='<?php namespace {namespace_prefix}\Providers; use Illuminate\Support\ServiceProvider; use App; class {facade_name_upcase}ServiceProvider extends ServiceProvider { public function boot() { // } public function register() { App::bind("{facade_name_lowercase}", function() { return new \{namespace_prefix}\Facades\{facade_name_upcase}; }); } } ' # {facade_name_upcase}Facade.php - FACADE TEMPLATE facade_template='<?php namespace {namespace_prefix}\Facades; use Illuminate\Support\Facades\Facade; class {facade_name_upcase}Facade extends Facade { protected static function getFacadeAccessor() { return "{facade_name_lowercase}"; } } ' } function checkDirectoryExists(){ if [ ! -d ${namespace_prefix_lowerfirstchar} ] then echo "" echo "Can't find the namespace: "${namespace_prefix_in} echo "" echo "*** NOTE:" echo " Make sure the namspace directory exists and" echo " you use quotes around the namespace_prefix." echo "" display_syntax exit fi } function makeDirectories(){ echo "Make Directories" echo "================" mkdir -p ${namespace_prefix_lowerfirstchar}/Facades mkdir -p ${namespace_prefix_lowerfirstchar}/Providers mkdir -p ${namespace_prefix_lowerfirstchar}/Facades } function createSourceTemplate(){ source_template=$(echo "${source_template}" | sed -e 's/{namespace_prefix}/'${namespace_prefix}'/g' -e 's/{facade_name_upcase}/'${facade_name_upcase}'/g' -e 's/{facade_name_lowercase}/'${facade_name_lowercase}'/g') echo "Create Source Template:" echo "=======================" echo "${source_template}" echo "" echo "${source_template}" > ./${namespace_prefix_lowerfirstchar}/Facades/${facade_name_upcase}.php } function createServiceProviderTemplate(){ serviceProvider_template=$(echo "${serviceProvider_template}" | sed -e 's/{namespace_prefix}/'${namespace_prefix}'/g' -e 's/{facade_name_upcase}/'${facade_name_upcase}'/g' -e 's/{facade_name_lowercase}/'${facade_name_lowercase}'/g') echo "Create ServiceProvider Template:" echo "================================" echo "${serviceProvider_template}" echo "" echo "${serviceProvider_template}" > ./${namespace_prefix_lowerfirstchar}/Providers/${facade_name_upcase}ServiceProvider.php } function createFacadeTemplate(){ facade_template=$(echo "${facade_template}" | sed -e 's/{namespace_prefix}/'${namespace_prefix}'/g' -e 's/{facade_name_upcase}/'${facade_name_upcase}'/g' -e 's/{facade_name_lowercase}/'${facade_name_lowercase}'/g') echo "Create Facade Template:" echo "=======================" echo "${facade_template}" echo "" echo "${facade_template}" > ./${namespace_prefix_lowerfirstchar}/Facades/${facade_name_upcase}Facade.php } function serviceProviderPrompt(){ echo "Providers: ${namespace_prefix_in}\Providers\\${facade_name_upcase}ServiceProvider," } function aliasPrompt(){ echo "Alias: '"${facade_name_upcase}"' => '"${namespace_prefix_in}"\Facades\\${facade_name_upcase}Facade'," } # # END FUNCTION DECLARATIONS # ########################### ## START RUNNING SCRIPT ## ########################### display_start_banner init_and_export_vars makeDirectories checkDirectoryExists echo "" createSourceTemplate createServiceProviderTemplate createFacadeTemplate echo "" echo "===========================" echo " Finished TEST" echo "===========================" echo "" echo "Add these lines to config/app.php:" echo "----------------------------------" serviceProviderPrompt aliasPrompt echo "" 

我使用的另一种方法是:1)在app \ FolderName \ fileName.php中创build一个文件,并在其中有这个代码即

 <?php namespace App\library { class hrapplication{ public static function libData(){ return "Data"; } } } ?> 

2)之后,在我们的刀片

  $FmyFunctions = new \App\FolderName\classsName; echo $is_ok = ($FmyFunctions->libData()); 

而已。 它的工作

编写自定义帮手的最佳实践是

1)在项目根目录的app目录下,创build一个名为Helpers的文件夹(只是为了分离和构造代码)。

2)在文件夹内写入psr-4文件或正常的php文件

如果PHP文件格式为psr-4,那么它将自动加载,否则在项目根目录内的composer.json中添加以下行

autoload键里面,新build一个名为files文件,在自动加载的时候加载文件,在files里面添加从app目录开始的path,这里是一个例子。

 "autoload": { "classmap": [ "database" ], "psr-4": { "App\\": "app/" }, "files": [ "app/Helpers/customHelpers.php" ] }, "autoload-dev": { "classmap": [ "tests/TestCase.php" ] }, 

PS:尝试运行composer dump-autoload如果文件不加载。

创build自定义助手的目录:首先在app目录下创build助手目录。 创buildhlper类定义:现在让我们创build一个简单的帮助函数,它将连接两个string。 在/app/Helpers/MyFuncs.php中创build一个新文件MyFuncs.php添加下面的代码

 <?php namespace App\Helpers; class MyFuncs { public static function full_name($first_name,$last_name) { return $first_name . ', '. $last_name; } } 

命名空间App \ Helpers; 定义App名称空间下的Helpers名称空间。 类MyFuncs {…}定义了辅助类MyFuncs。 公共静态函数full_name($ first_name,$ last_name){…}定义了一个静态函数,它接受两个string参数并返回一个连接的string

助手服务提供类

服务提供者用于自动加载类。 我们需要定义一个服务提供者,它将把所有的帮助类加载到/ app / Helpers目录中。

运行下面的工匠命令:

PHP的工匠使:提供者HelperServiceProvider

该文件将在/app/Providers/HelperServiceProvider.php创build

 Open /app/Providers/HelperServiceProvider.php 

添加下面的代码:

 <?php namespace App\Providers; use Illuminate\Support\ServiceProvider; class HelperServiceProvider extends ServiceProvider { /** * Bootstrap the application services. * * @return void */ public function boot() { // } /** * Register the application services. * * @return void */ public function register() { foreach (glob(app_path().'/Helpers/*.php') as $filename){ require_once($filename); } } } 

这里,

 namespace App\Providers; defines the namespace provider use Illuminate\Support\ServiceProvider; imports the ServiceProvider class namespace class HelperServiceProvider extends ServiceProvider {…} defines a class HelperServiceProvider that extends the ServiceProvider class public function boot(){…} bootstraps the application service public function register(){…} is the function that loads the helpers foreach (glob(app_path().'/Helpers/*.php') as $filename){…} loops through all the files in /app/Helpers directory and loads them. 

我们现在需要注册HelperServiceProvider并为我们的助手创build一个别名。

打开/config/app.php文件

find提供程序数组variables

添加以下行

 App\Providers\HelperServiceProvider::class, 

find别名数组variables

添加以下行

 'MyFuncs' => App\Helpers\MyFuncs::class, 

保存更改使用我们的自定义帮助程序

我们将创build一个将调用我们的自定义帮助函数Open /app/routes.php的路由

添加以下路由定义

 Route::get('/func', function () { return MyFuncs::full_name("John","Doe"); }); 

这里,

 return MyFuncs::full_name("John","Doe"); calls the static function full_name in MyFuncs class 

在dir bootstrap \ autoload.php中

 require __DIR__.'/../vendor/autoload.php'; require __DIR__.'/../app/Helpers/function.php'; //add 

添加这个文件

 app\Helpers\function.php 

在laravel 5.3及以上版本中,laravel团队将所有程序文件( routes.php )移出app/目录,整个app/文件夹是psr-4自动加载的。 接受的答案将在这种情况下工作,但它不适合我。

所以我所做的是在我的项目的根目录下创build了一个helpers/目录,并将帮助文件放在里面,在我的composer.json文件中,我这样做了:

 ... "autoload": { "classmap": [ "database" ], "psr-4": { "App\\": "app/" }, "files": [ "helpers/ui_helpers.php" ] }, ... 

这样,我的app/目录仍然是一个psr-4自动加载,并且帮手组织得好一点。

希望这有助于某人。

这里有一些很好的答案,但我认为这是最简单的。 在Laravel5.4(以及早期的版本)中,你可以创build一个方便你的类,比如App / Libraries / Helper.php

 class Helper() { public function uppercasePara($str) { return '<p>' .strtoupper($str). '<p>; } } 

然后你可以简单地在你的Blade模板中调用它:

 @inject('helper', \App\Libraries\Helper) {{ $helper->drawTimeSelector() }} 

如果您不想使用@inject,那么只需将“uppercasePara”函数设置为静态,并将调用embedded到您的Blade模板中,如下所示:

 {{ \App\Libraries\Helper::drawTimeSelector() }} 

不需要别名。 Laravel自动parsing具体的类。

首先在App \ Http目录下创buildhelpers.php。 然后在composer.json中添加下面的代码

 "autoload": { "classmap": [ "database" ], "files": [ "app/Http/helpers.php" ], "psr-4": { "App\\": "app/" } }, 

接下来运行以下命令

 composer dump-autoload 

现在你可以在helpers.php文件中定义你的自定义函数。 在这里你可以得到完整的指南