Helpex - Trao đổi & giúp đỡ Đăng nhập
62

Tuần trước, tôi đã biết rằng các lớp có thể được đưa vào dự án của bạn bằng cách viết một __autoload()hàm. Sau đó, tôi học được rằng việc sử dụng trình tải tự động không chỉ là một kỹ thuật mà còn là một mô hình.

Bây giờ tôi đang sử dụng trình tải tự động trong dự án của mình và tôi thấy nó rất hữu ích. Tôi đã tự hỏi liệu có thể làm điều tương tự với các hàm không. Có thể rất hữu ích nếu bạn quên việc bao gồm tệp PHP phù hợp với các hàm bên trong nó.

Vì vậy, có thể tạo một chức năng autoloader?

62 hữu ích 1 bình luận 28k xem chia sẻ
11 trả lời 11
62

Không có chức năng tự động nạp chức năng cho các chức năng. Bạn có bốn giải pháp thực tế:

  1. Gói tất cả các chức năng vào các lớp không gian tên (phù hợp với ngữ cảnh). Vì vậy, giả sử bạn có một hàm được gọi string_get_letters. Bạn có thể thêm nó vào một lớp được gọi StringFunctionslà một hàm tĩnh. Vì vậy, thay vì gọi string_get_letters(), bạn sẽ gọi StringFunctions::get_letters(). Sau đó, bạn sẽ có __autoloadcác lớp không gian tên.

  2. Tải trước tất cả các chức năng. Vì bạn đang sử dụng các lớp học, bạn không nên có nhiều chức năng, vì vậy chỉ cần pre-load chúng.

  3. Tải các chức năng trước khi sử dụng chúng. Trong mỗi tệp, require_oncecác tệp chức năng sẽ được sử dụng trong tệp đó.

  4. Không sử dụng các chức năng ngay từ đầu. Nếu bạn đang phát triển mã OOP (có vẻ như bạn vẫn đang sử dụng), sẽ có rất ít hoặc không cần đến các chức năng. Mọi thứ bạn cần một chức năng (hoặc nhiều), bạn có thể xây dựng theo cách OO và tránh nhu cầu về chức năng.

Cá nhân tôi đề xuất 1, 2 hoặc 4 tùy thuộc vào nhu cầu chính xác của bạn cũng như chất lượng và kích thước cơ sở mã của bạn ...

62 hữu ích 5 bình luận chia sẻ
39

Nếu bạn đang sử dụng Composer trong Dự án của mình, bạn có thể thêm chỉ thị tệp vào phần tự động tải.

Điều này sẽ không thực sự tạo ra một request_once trong trình tải tự động, nhưng nó giống như tự động tải thực sự, vì bạn không phải quan tâm đến điều đó.
Mặc dù nó không tải chậm.

Ví dụ lấy từ Assetic :

"autoload": {
        "psr-0": { "Assetic": "src/" },
        "files": [ "src/functions.php" ]
    }
39 hữu ích 3 bình luận chia sẻ
15

Tôi đã đọc một cái gì đó một thời gian về một vụ hack xấu xí mắc lỗi nghiêm trọng và cố gắng bao gồm và thực thi (các) chức năng bị thiếu, nhưng tôi chắc chắn sẽ không đi con đường đó.

Thứ gần nhất bạn có là __call() phương thức ma thuật , là một __autoload()phương thức cho các phương thức, không phải hàm. Nó có thể đủ tốt cho nhu cầu của bạn; nếu bạn có đủ khả năng để gọi một lớp và yêu cầu từng chức năng khác nhau riêng biệt. Kể từ PHP 5.3.0, bạn cũng có __callStatic().

Một ví dụ sử dụng __callStatic():

class Test
{
    public function __callStatic($m, $args)
    {
        if (function_exists($m) !== true)
        {
            if (is_file('./path/to/functions/' . $m . '.php') !== true)
            {
                return false;
            }

            require('./path/to/functions/' . $m . '.php');
        }

        return call_user_func_array($m, $args);
    }
}

Test::functionToLoad(1, 2, 3);

Điều này sẽ gọi functionToLoad()hàm được định nghĩa trong ./path/to/functions/ Chức năngToLoad.php.

15 hữu ích 5 bình luận chia sẻ
8

Như thường lệ, có một phần mở rộng PECL cho điều đó:

(thông qua: http://phk.tekwire.net/joomla/support/doc/automap.htm )

Nó phải tự động tải các hàm cũng như các lớp. Tuy nhiên, điều này vẫn chưa hoạt động với trình thông dịch PHP hiện tại.

(Một tùy chọn thay thế btw, đang tạo ra các hàm sơ khai để tải và chạy các đối tác có không gian tên.)

Điều đó đang được nói. Tự động tải không được coi là một phương pháp hay. Nó dẫn đến phân cấp giai cấp bị rạn nứt quá mức và đối tượng hạnh phúc. Và lý do thực sự mà PHP có tính năng tự động tải là do hệ thống quản lý bao gồm và phụ thuộc chưa hoàn thiện.

8 hữu ích 0 bình luận chia sẻ
3
namespace MyNamespace;

class Fn {

    private function __construct() {}
    private function __wakeup() {}
    private function __clone() {}

    public static function __callStatic($fn, $args) {
        if (!function_exists($fn)) {
            $fn = "YOUR_FUNCTIONS_NAMESPACE\\$fn";
            require str_replace('\\', '/', $fn) . '.php';
        }
        return call_user_func_array($fn, $args);
    }

}

Và sử dụng không gian tên, chúng ta có thể làm: Fn::myFunc()spl_autoload_register(). Tôi đã sử dụng mã này với các ví dụ tại: https://goo.gl/8dMIMj

3 hữu ích 3 bình luận chia sẻ
1

Tôi sử dụng Lớp học và __invoke . Các __invokephương pháp được gọi khi một kịch bản gọi một lớp học như một hàm. Tôi thường làm điều gì đó như thế này:

<?php

namespace API\Config;

class Slim {
  function __invoke() {
    return [
      'settings' => [
        'displayErrorDetails' => true,
        'logger' => [
          'name' => 'api',
          'level' => Monolog\Logger\Logger::DEBUG,
          'path' => __DIR__ . '/../../logs/api.log',
        ],
      ]
    ];
  }
}

Sau đó, tôi có thể gọi như một hàm:

$config = API\Config\Slim;
$app = Slim\App($config())
1 hữu ích 2 bình luận chia sẻ
1

new Functions \ Debug () sẽ tải các hàm vào không gian tên gốc.

Các chức năng vùng tên
{

    gỡ lỗi lớp
    {
    }
}
không gian tên
{

    if (! function_exists ('printr')) {

        / **
         *
         * @param hỗn hợp $ biểu thức
         * /
        function printr ()
        {
            foreach (func_get_args () as $ v) {
                if (is_scalar ($ v)) {
                    echo $ v. "\ n";
                } khác {
                    print_r ($ v);
                }
            }
            lối ra();
        }
    }
}
1 hữu ích 0 bình luận chia sẻ
0

Đây là một ví dụ khá phức tạp khác, dựa trên các gợi ý trong cuộc thảo luận này. Mã cũng có thể được nhìn thấy ở đây: lib / btr.php

<?php
/**
 * A class that is used to autoload library functions.
 *
 * If the function btr::some_function_name() is called, this class
 * will convert it into a call to the function
 * 'BTranslator\some_function_name()'. If such a function is not
 * declared then it will try to load these files (in this order):
 *   - fn/some_function_name.php
 *   - fn/some_function.php
 *   - fn/some.php
 *   - fn/some/function_name.php
 *   - fn/some/function.php
 *   - fn/some/function/name.php
 * The first file that is found will be loaded (with require_once()).
 *
 * For the big functions it makes more sense to declare each one of them in a
 * separate file, and for the small functions it makes more sense to declare
 * several of them in the same file (which is named as the common prefix of
 * these files). If there is a big number of functions, it can be more
 * suitable to organize them in subdirectories.
 *
 * See: http://stackoverflow.com/questions/4737199/autoloader-for-functions
 */
class btr {
  /**
   * Make it TRUE to output debug info on '/tmp/btr.log'.
   */
  const DEBUG = FALSE;

  /**
   * The namespace of the functions.
   */
  const NS = 'BTranslator';

  /**
   * Relative directory where the functions are located.
   */
  const FN = 'fn';

  private function __construct() {}
  private function __wakeup() {}
  private function __clone() {}

  /**
   * Return the full name (with namespace) of the function to be called.
   */
  protected static function function_name($function) {
    return self::NS . '\\' . $function;
  }

  /**
   * Return the full path of the file to be loaded (with require_once).
   */
  protected static function file($fname) {
    return dirname(__FILE__) . '/' . self::FN . '/' . $fname . '.php';
  }

  /**
   * If a function does not exist, try to load it from the proper file.
   */
  public static function __callStatic($function, $args) {
    $btr_function = self::function_name($function);
    if (!function_exists($btr_function)) {
      // Try to load the file that contains the function.
      if (!self::load_search_dirs($function) or !function_exists($btr_function)) {
        $dir = dirname(self::file($fname));
        $dir = str_replace(DRUPAL_ROOT, '', $dir);
        throw new Exception("Function $btr_function could not be found on $dir");
      }
    }
    return call_user_func_array($btr_function, $args);
  }

  /**
   * Try to load files from subdirectories
   * (by replacing '_' with '/' in the function name).
   */
  protected static function load_search_dirs($fname) {
    do {
      self::debug($fname);
      if (file_exists(self::file($fname))) {
        require_once(self::file($fname));
        return TRUE;
      }
      if (self::load_search_files($fname)) {
        return TRUE;
      }
      $fname1 = $fname;
      $fname = preg_replace('#_#', '/', $fname, 1);
    } while ($fname != $fname1);

    return FALSE;
  }

  /**
   * Try to load files from different file names
   * (by removing the part after the last undescore in the functin name).
   */
  protected static function load_search_files($fname) {
    $fname1 = $fname;
    $fname = preg_replace('/_[^_]*$/', '', $fname);
    while ($fname != $fname1) {
      self::debug($fname);
      if (file_exists(self::file($fname))) {
        require_once(self::file($fname));
        return TRUE;
      }
      $fname1 = $fname;
      $fname = preg_replace('/_[^_]*$/', '', $fname);
    }

    return FALSE;
  }

  /**
   * Debug the order in which the files are tried to be loaded.
   */
  public static function debug($fname) {
    if (!self::DEBUG) {
      return;
    }
    $file = self::file($fname);
    $file = str_replace(DRUPAL_ROOT, '', $file);
    self::log($file, 'Autoload');
  }

  /**
   * Output the given parameter to a log file (useful for debugging).
   */
  public static function log($var, $comment ='') {
    $file = '/tmp/btr.log';
    $content = "\n==> $comment: " . print_r($var, true);
    file_put_contents($file, $content, FILE_APPEND);
  }
}
0 hữu ích 0 bình luận chia sẻ
0

Mặc dù bạn không thể tự động tải các hàm và hằng số, nhưng bạn có thể sử dụng một cái gì đó như jesseschalken / autoload-creator sẽ tự động phát hiện những tệp nào chứa những thứ không thể tự động tải và tải chúng một cách háo hức.

0 hữu ích 0 bình luận chia sẻ
0

Bao gồm tất cả các tệp chức năng trong một tệp và sau đó bao gồm nó

// Tệp 1
db_fct.php

// Tệp 2
use_fct.php

// Trong một functions.php bao gồm tất cả các tệp khác

<?php

require_once 'db_fct.php';
require_once 'util_fct.php';
?>

Bao gồm các functions.php bất cứ khi nào bạn cần các chức năng ..

0 hữu ích 3 bình luận chia sẻ
-2

thử cái này

if ($handle = opendir('functions')) {
    while (false !== ($entry = readdir($handle))) {
        if (strpos($entry, '.php') !== false) {
            include("functions/$entry");
        }
    }
    closedir($handle);
}
-2 hữu ích 1 bình luận chia sẻ
loading
Không tìm thấy câu trả lời bạn tìm kiếm? Duyệt qua các câu hỏi được gắn thẻ php function class autoloader , hoặc hỏi câu hỏi của bạn.

Có thể bạn quan tâm

loading