2011-12-28 40 views
11

Tôi đang xử lý một ứng dụng web sử dụng hệ thống tạo khuôn mẫu được phát triển tại nhà cho phép mã Perl được nhúng trong HTML. Các câu lệnh này được thực hiện bởi trình phân tích mẫu tại thời gian chạy bằng cách sử dụng eval EXPR.Thay thế nhanh hơn cho eval?

Điều này rất linh hoạt, nhưng các báo cáo này nằm rải rác ở khắp mọi nơi và được thực thi . eval EXPR (trái ngược với eval BLOCK) yêu cầu Perl kích hoạt trình thông dịch mỗi lần và tiểu sử của tôi cho thấy rằng chúng là nguồn đáng kể đáng kể chậm lại.

Nhiều câu lệnh Perl được nhúng rất đơn giản. Ví dụ, một mẫu có thể có một dòng như sau:

<p>Welcome, <!--E: $user->query('name') -->. 

Hoặc:

<p>Ticket number <!--E: $user->generate_ticket_number() --> has been generated. 

Đó là, chúng tôi chỉ gọi phương pháp đối tượng. Tuy nhiên, có những phức tạp hơn.

Tôi hy vọng tối ưu hóa điều này, và cho đến nay có hai ý tưởng, cả hai đều là khủng khiếp. Đầu tiên là viết lại tất cả các mẫu để thay thế các cuộc gọi đơn giản bằng các mã thông báo như USER:NAMEUSER:GENERATETICKETNUMBER, mà trình phân tích cú pháp có thể quét và gọi phương thức đối tượng thích hợp. Nhưng sau đó thay vì xử lý các mẫu kết hợp HTML và Perl, tôi sẽ có các mẫu kết hợp HTML, Perl và các thẻ. Ý tưởng thứ hai là cố gắng phân tích cú pháp Perl được nhúng, tìm ra câu lệnh muốn làm gì và nếu đủ đơn giản, hãy gọi phương thức đối tượng thích hợp thông qua một tham chiếu tượng trưng. Điều này rõ ràng là điên rồ.

Có một số giải pháp hợp lý mà tôi đang xem không?

+1

+1 cho "Điều này rõ ràng là điên". –

Trả lời

9

Hãy thử dùng một cách tiếp cận tương tự như một trong đó mod_perl sử dụng để biên dịch CGI:

  1. Chuyển đổi mẫu vào mã Perl. Ví dụ, ví dụ đầu tiên của bạn có thể chuyển đổi sang một cái gì đó như:

    print "<p>Welcome, "; 
    print $user->query('name'); 
    print ".\n"; 
    
  2. Quấn một sub { ... } xung quanh mã mà, cùng với một số mã để giải nén đối số (ví dụ, đối với những thứ như $user trong mẫu).

  3. eval mã đó. Lưu ý rằng nó trả về một coderef.

  4. Gọi mã đó liên tục. :)

+5

Cách tiếp cận có liên quan là viết mã được tạo ra thành tệp '.pm' và sau đó tải mô-đun đó. Bằng cách đó, các mẫu sẽ chỉ cần được reparsed khi nó thay đổi. Cách nào tốt hơn phụ thuộc vào chi tiết về cách ứng dụng được triển khai. – cjm

+0

Ồ, thật tuyệt vời! Nó cho phép tôi khắc phục vấn đề mà không cần phải viết lại một mẫu gazillion. Tôi sẽ thử nó, cảm ơn bạn! – parsim

+0

Đây chính xác là những gì [Template Toolkit] (http://template-toolkit.org) thực hiện. –

2

Bạn có thể muốn nhìn vào ruột của Text::MicroTemplate. Thực tế, bạn có thể muốn sử dụng Văn bản :: MicroTemplate, vì nó có thể phù hợp với nhu cầu của bạn. Nó xây dựng một chương trình con nối các chuỗi khi cần, giống như duskwuff gợi ý. Dưới đây là kết quả của build_mt('hello, <?= $_[0] ?>') trong re.pl:

$CODE1 = sub { 
     package Devel::REPL::Plugin::Packages::DefaultScratchpad; 
     use warnings; 
     use strict 'refs'; 
     local $SIG{'__WARN__'} = sub { 
     print STDERR $_mt->_error(shift(), 4, $_from); 
     } 
     ; 
     Text::MicroTemplate::encoded_string(sub { 
     my $_mt = ''; 
     local $_MTREF = \$_mt; 
     my $_from = ''; 
     $_mt .= 'hello, '; 
     $_from = $_[0]; 
     $_mt .= ref $_from eq 'Text::MicroTemplate::EncodedString' ? $$_from : do { 
      $_from =~ s/([&><"'])/$Text::MicroTemplate::_escape_table{$1};/eg; 
      $_from 
     }; 
     return $_mt; 
     } 
     ->(@_)); 
    }; 
+0

Cảm ơn sự giúp đỡ! Tôi hy vọng thoát khỏi điều này mà không cần phải thay thế hệ thống templating hiện tại, vì đó sẽ là một công việc khá lớn. Nhưng nếu nó trở thành quá nhiều rắc rối, tôi sẽ xem xét MicroTemplate. – parsim

3

Bạn có thể có một cái nhìn tại Mojolicious. Nó có một templating engine cho phép một cú pháp gần với những gì bạn đang sử dụng.Bạn có thể có thể chuyển sang sử dụng nó hoặc nhìn vào nguồn của nó (nhấp vào nguồn bên trái của liên kết trước đó) để xem bạn có thể vẽ một số ý tưởng hay không.

FYI cú pháp khuôn mẫu động cơ của Mojolcious cho phép các hình thức sau trộn lẫn với HTML một cách thích hợp

<% Perl code %> 
<%= Perl expression, replaced with result %> 
<%== Perl expression, replaced with XML escaped result %> 
<%# Comment, useful for debugging %> 
<%% Replaced with "<%", useful for generating templates %> 
% Perl code line, treated as "<% line =%>" 
%= Perl expression line, treated as "<%= line %>" 
%== Perl expression line, treated as "<%== line %>" 
%# Comment line, treated as "<%# line =%>" 
%% Replaced with "%", useful for generating templates 
+0

Cảm ơn! Khi tôi đăng lên Josh, tôi hy vọng sẽ tránh phải thay thế toàn bộ hệ thống templating, chỉ vì nó là một phần mềm 10 năm tuổi và những thứ đó khó sửa đổi. Nhưng tôi đã nghe những điều tốt đẹp về Mojolicious. – parsim

+0

Tôi hoàn toàn hiểu! Tuy nhiên có lẽ mã của nó có thể giúp bạn với một vài ý tưởng. –

+1

@JoelBerger ở mọi nơi khác, câu hỏi này sẽ nhận được phản hồi "Sử dụng Idiot". 1 để trở thành người bạn tuyệt vời của tôi. – Hawken

0

Bạn không nên sử dụng 'eval' để gọi các phương thức trong mẫu của bạn. Xin lỗi để âm thanh khắc nghiệt nhưng điểm của một cái nhìn riêng biệt là để loại bỏ các mã xử lý từ lớp xem. Các hệ thống mẫu được mô tả ở trên cùng với Bộ công cụ mẫu chỉ cần truyền vào một đối tượng/băm để bạn có thể truy cập nó.

tại sao không vượt qua $ user như một hashref như:

$user = { 
     'name' => 'John', 
     'id' => '3454' 
     }; 

này sẽ cho phép bạn truy cập vào 'tên' với:

$user->{'name'}; 

Nếu không, nó có khả năng mà bạn có mà bạn làm một cái gì đó như:

  1. mẫu gọi $ user-> query();
  2. phương pháp gọi DB để có được giá trị
  3. phương pháp trả về giá trị

Đó là soooo đắt hơn nhiều để thực hiện một truy vấn cơ sở dữ liệu hơn để vượt qua các tài liệu tham khảo băm/đối tượng cho mẫu. Bạn có thể muốn kiểm tra một số công cụ định dạng mã như Devel :: NYTProf để xem phần nào của việc thực thi mã thực sự làm chậm bạn xuống. Tôi nghi ngờ rằng eval là bogging xuống chương trình của bạn rất nhiều mà bạn cần phải tối ưu hóa ra eval. Âm thanh như mã bên trong eval là những gì đang làm chậm bạn xuống.

+0

Tôi đã chạy NYTProf, và có vẻ như để cho biết bản thân eval là một nguồn đáng kể chậm lại. Nó chỉ tiêu thụ 5-10% tổng thời gian máy chủ, nhưng nó cũng là điểm lớn nhất duy nhất. Nó không thực sự khả thi để thay thế các cuộc gọi $ user-> query ($ value) với $ user -> {$ value} dưới dạng & query sub thường thực sự làm điều gì đó ngoài việc tìm kiếm giá trị. Ngoài ra, đó chỉ là một cuộc gọi giữa nhiều người. – parsim

+0

phân tích cú pháp, tại sao bạn gọi các trình con để thực hiện công việc ở lớp chế độ xem? Không phải tất cả công việc đó sẽ được chăm sóc trước khi xuất kết quả? Có lẽ bạn cần xem xét việc tạo một loại API khác? Nếu bạn đang gọi do tương tác của người dùng, có thể là thời gian cho một số cuộc gọi phía máy chủ thông qua AJAX. –

+0

Câu trả lời là ứng dụng web không có kiến ​​trúc MVC. (Tôi đã đề cập đến nó gần 10 tuổi chưa?) Các mẫu có hiệu quả thúc đẩy ứng dụng. Nó sẽ là một công việc rất lớn để thay đổi điều này, vì vậy tôi bị mắc kẹt với nó. – parsim

Các vấn đề liên quan